Ali*_*eeb 2 concurrency multithreading grand-central-dispatch swift
在我的应用程序中,我必须在后台同时解压缩多个文件。哪个代码会在多个线程上并行执行compressedFiles数组:
for file in compressedFiles {
DispatchQueue.global(qos: .userInteractive).async {
let work = DispatchGroup()
work.enter()
file.decompress()
work.leave()
}
}
Run Code Online (Sandbox Code Playgroud)
或者:
DispatchQueue.global(qos: .userInteractive).async {
for file in compressedFiles {
let work = DispatchGroup()
work.enter()
file.decompress()
work.leave()
}
}
Run Code Online (Sandbox Code Playgroud)
另外,如果我想在其中一个文件解压过程完成后收到通知,如何利用 DispatchGroup 类?wait()和notify()放在哪里?
谢谢。
您的第二个示例将按顺序运行它们。它正在执行一次调度,一个接一个地运行它们。您的第一个示例将并行运行它们,将每个线程分派到不同的工作线程。但不幸的是,两者都没有正确使用调度组。
关于调度组,您应该在循环之前和enter调用之前定义它async。但仅当您从调用中调用异步进程时才需要手动调用enter和。但考虑到这可能是一个同步过程,您只需将组提供给,它就会为您处理一切:leaveasyncdecompressasync
let group = DispatchGroup()
for file in compressedFiles {
DispatchQueue.global(qos: .userInteractive).async(group: group) {
file.decompress()
}
}
group.notify(queue: .main) {
// all done
}
Run Code Online (Sandbox Code Playgroud)
但与其担心调度组逻辑,并行示例中还存在更深层次的问题。具体来说,它会遭受线程爆炸的影响,可能会超过 CPU 上的可用内核数量。更糟糕的是,如果您有大量文件需要解压,甚至可能会超出 GCD 池中工作线程的限制数量。当这种情况发生时,它可以阻止任何其他东西在 GCD 上运行以实现该 QoS。相反,您希望并行运行它,但希望将其限制在合理的并发程度,同时仍然享受并行性,以避免耗尽其他任务的资源。
如果您希望它并行运行,但又避免线程爆炸,通常会选择concurrentPerform. 这提供了 CPU 支持的最大并行度,同时防止了线程爆炸可能导致的问题:
DispatchQueue.global(qos: .userInitiated).async {
DispatchQueue.concurrentPerform(iterations: compressedFiles.count) { index in
compressedFiles[index].decompress()
}
DispatchQueue.main.async {
// all done
}
}
Run Code Online (Sandbox Code Playgroud)
这会将并行度限制为设备上内核允许的最大程度。它还消除了对调度组的需要。
或者,如果您想享受并行性,但并发程度较低(例如,让一些核心可用于其他任务,最大限度地减少峰值内存使用等),您可以使用使用操作队列和maxConcurrentOperationCount:
let queue = OperationQueue()
queue.maxConcurrentOperationCount = 4 // a max of 4 decompress tasks at a time
let completion = BlockOperation {
// all done
}
for file in compressedFiles {
let operation = BlockOperation {
file.decompress()
}
completion.addDependency(operation)
queue.addOperation(operation)
}
OperationQueue.main.addOperation(completion)
Run Code Online (Sandbox Code Playgroud)
或者 Matt 指出,在 iOS 13(或 macOS 10.15)及更高版本中,您可以执行以下操作:
let queue = OperationQueue()
queue.maxConcurrentOperationCount = 4
for file in compressedFiles {
queue.addOperation {
file.decompress()
}
}
queue.addBarrierBlock {
DispatchQueue.main.async {
// all done
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2878 次 |
| 最近记录: |