【发布时间】:2017-01-27 23:09:11
【问题描述】:
我的第一个问题!
我正在对视频源进行 CPU 密集型图像处理,并且我想使用 OperationQueue。然而,结果绝对是可怕的。这是一个示例——假设我有一个 CPU 密集型操作:
var data = [Int].init(repeating: 0, count: 1_000_000)
func run() {
let startTime = DispatchTime.now().uptimeNanoseconds
for i in data.indices { data[i] = data[i] &+ 1 }
NSLog("\(DispatchTime.now().uptimeNanoseconds - startTime)")
}
在我的笔记本电脑上执行大约需要 40 毫秒。我计时一百次:
(1...100).forEach { i in run(i) }
它们平均每个大约 42 毫秒,总共大约 4200 毫秒。我有 4 个物理内核,所以我尝试在 OperationQueue 上运行它:
var q = OperationQueue()
(1...100).forEach { i in
q.addOperation {
run(i)
}
}
q.waitUntilAllOperationsAreFinished()
有趣的事情发生取决于 q.maxConcurrentOperationCount:
concurrency single operation total
1 45ms 4500ms
2 100-250ms 8000ms
3 100-300ms 7200ms
4 250-450ms 9000ms
5 250-650ms 9800ms
6 600-800ms 11300ms
我使用.background的默认QoS,可以看到线程优先级是默认的(0.5)。查看 Instruments 的 CPU 利用率,我看到很多浪费的周期(第一部分在主线程上运行,第二部分在 OperationQueue 上运行):
我用 C 语言编写了一个简单的线程队列,并在 Swift 中使用了它,它随内核线性扩展,因此我的速度提高了 4 倍。但是我在 Swift 上做错了什么?
更新: 我认为我们已经得出结论,这是 DispatchQueue 中的一个合法错误。那么问题实际上是在 DispatchQueue 代码中询问问题的正确渠道是什么?
【问题讨论】:
-
没有数据冲突吗?一个线程由于其他线程在同一索引处写入而被锁定?
-
Marek,有,但我不关心计算的结果,我只需要一个持续约 50 毫秒的计算。
-
尝试让 run func 作为一个 NSOperation 子类
标签: swift multithreading macos performance