multithreading - Swift:如何中断排序例程
问题描述
如果需要太长时间,我想让用户能够停止排序程序。
我尝试使用 DispatchWorkItem.cancel。但是,这实际上并没有停止已经启动的进程。
let myArray = [String]() // potentially 230M elements!
...
workItem = DispatchWorkItem {
let result = myArray.sorted()
DispatchQueue.main.async {
print ("done")
}
}
// 如果进程太长,用户点击“取消” => workItem.cancel() // 不会停止排序
如何杀死 workItem 的线程?
我无权访问已排序的例程,因此我无法插入测试以检查当前线程是否处于“已取消”状态...
解决方案
isCancelled
正如您所推断的,如果不定期检查并手动执行提前退出(如果已设置),则根本无法杀死工作项。
有两种选择:
您可以在那里使用
sorted(by:)
, 测试,isCancelled
如果它被取消则抛出错误。这实现了预期的提前退出。这可能看起来像:
func cancellableSort() -> DispatchWorkItem { var item: DispatchWorkItem! item = DispatchWorkItem() { let unsortedArray = (0..<10_000_000).shuffled() let sortedArray = try? unsortedArray.sorted { (obj1, obj2) -> Bool in if item.isCancelled { throw SortError.cancelled } return obj1 < obj2 } // do something with your sorted array item = nil } DispatchQueue.global().async(execute: item) return item }
在哪里
enum SortError: Error { case cancelled }
请注意,即使在发布版本中,这也会对性能产生巨大影响。所以你可能想对此进行基准测试。
您可以编写自己的排序例程,
isCancelled
在算法中插入您自己的测试。这使您可以更好地控制执行测试的精确位置(即,您可能不想在每次比较时都这样做,而是在算法中的某个更高级别的循环中进行,从而最大限度地减少对性能的影响)。鉴于记录的数量,这使您有机会选择最适合您的数据集的算法。
显然,在对这些替代方案进行基准测试时,请确保您测试优化/发布版本,以便您的结果不会因构建设置而出现偏差。
顺便说一句,您也可以考虑使用Operation
,因为它对取消的处理更加优雅,恕我直言。另外,您可以有一个专门的对象用于排序操作,这样更干净。
推荐阅读
- javascript - Select changed by javascript 无法触发 change 事件
- mysql - WP_Query 通过 REGEX 搜索 post_title
- azure-pipelines - Azure devops 发布管道以使用 BTDF 部署 BizTalk 应用程序
- python - PgBouncer:关闭,因为:客户端关闭请求并关闭,因为:服务器不干净
- google-cloud-platform - Python Google API Campaign Manager 插入广告素材资产显示成功,但未出现在广告客户中
- javascript - 带有数据集的 jQuery 元素
- vue.js - 在 vue js 中传递 HTML 标签
- c# - 如何使用 C# .net 访问 Rider IDE 中的 MySql 或 Postgres 数据库进行控制台应用程序?
- typescript - Typescript:如何通过接口类型传递 9999999999999999?
- ios - 如何制作自定义标签栏?