假设我有一个提供一些长时间操作的函数。
func foo(parameter: String)
这个功能是同步的,我无法更改。
我需要在参数数组上运行该函数:
stringArray.forEach { foo($0) }
显然这需要时间。
我更喜欢创建一个异步函数来使其异步,如下所示:
func manyFoo(parameters: [String]) async {
await withTaskGroup(of: Void.self) { group in
for parameter in parameters {
group.addTask { foo(parameter: parameters) }
}
}
}
但是它真的同时执行
foo
吗?
你问:
但是它真的同时执行
吗?foo
是的,确实如此,假设
foo
不是演员隔离的。显然,如果 foo
与任何特定参与者隔离,那么尽管使用了任务组,但这仍将阻止并行执行。然后,再次强调,如果 foo
是 actor 隔离的,那么编译器会警告您必须 await
它。
FWIW,我添加了一些
OSSignposter
日志记录,对其进行了分析,并在 Instruments 的“兴趣点”和“Swift 任务”工具中观看了它:
您可以看到,在我的 iPhone 13 Pro Max 上,我获得了六个并发任务。
那是:
import os.log
private let poi = OSSignposter(subsystem: "Test", category: .pointsOfInterest)
class Experiment {
let lock = NSLock()
func foo(parameter: String) {
let state = lock.withLock {
let id = poi.makeSignpostID()
return poi.beginInterval("foo", id: id, "\(parameter)")
}
…
lock.withLock {
poi.endInterval("foo", state)
}
}
}
请注意,要看到性能方面的任何实质性改进,您需要确保每个任务都有足够的工作来证明并发引入的适度开销是合理的。例如,如果您有 100 万个字符串,每个字符串需要 20 毫秒,那么实际上可能会更慢。因此,您可能需要进行“跨越”(例如,100 个任务,每个任务处理 10,000 个字符串)。
或者,如果您的任务都与某些共享资源(例如文件)交互,您可能根本无法实现任何性能改进。
在不知道您的同步任务正在做什么的情况下,我们无法进一步发表评论。