如何在@MainActor类中让async函数在后台线程执行?
如何在后台线程运行@MainActor类中的耗时同步CPU密集型async函数?
我有一个标注@MainActor的类,其中包含一个async函数,这个函数执行耗时的同步CPU密集型操作:
@MainActor class MyClass { // ... func getFoo() async -> Foo { let foo = // ... 一些耗时的同步CPU密集型操作 ... return foo } // ... }
我想让这个函数在后台线程运行以避免阻塞主线程,见过两种实现方案,但不确定哪种正确(或是否都正确),因为两种方案都有反对观点。
两种常见实现方案
1. Task.detached方案
func getFoo() async -> Foo { await Task.detached { let foo = // ... 一些耗时的同步CPU密集型操作 ... return foo }.value }
2. Continuation + GCD方案
func getFoo() async -> Foo { await withCheckedContinuation { continuation in DispatchQueue.global().async { let foo = // ... 一些耗时的同步CPU密集型操作 ... continuation.resume(returning: foo) } } }
反对Task.detached方案的观点
无论是否在主actor中,都不应在并发上下文运行长期耗时的阻塞操作。Swift并发是协作式模型,即并发上下文中的函数应定期挂起以释放线程控制权,让运行时能在该线程上调度其他任务。
回想一下,Swift语言让我们能维护线程始终可向前推进的运行时契约。基于此契约,我们构建了协作式线程池作为Swift的默认执行器。采用Swift并发时,需确保代码维持该契约,以让协作式线程池最优运行。
根据以上观点,耗时同步操作不应在Swift并发中执行,否则会阻塞线程推进并违反运行时契约。我原本以为Continuation + GCD是替代方案,但该方案也存在反对观点。
反对Continuation + GCD方案的观点
应完全避免使用DispatchQueue。
我会避免引入GCD,因为它不参与协作式线程池,Swift并发无法合理调度系统资源、避免线程爆炸等。
那么,到底如何正确地让这个async函数在后台线程运行?
内容的提问来源于stack exchange,提问作者NSExceptional
相关产品推荐
相关产品推荐

