将阻塞函数集成到 Swift async 中

zap*_*oyd 4 async-await swift swift-concurrency

我知道异步 SwiftTask不应该阻塞(异步工作线程必须始终向前推进)。如果我有一个 100% 异步 Swift 应用程序,但需要引入一些阻塞任务,那么正确的方法是什么,不会阻塞任何 swift 异步线程池工作线程?

我假设需要异步线程池之外的新专用线程,如果该假设正确,异步函数等待该线程完成的线程安全方法是什么?我可以使用 的主体withCheckedContinuation来启动线程,将continuation句柄复制到该线程中并continuation.resume在线程完成时从该线程调用吗?

Ita*_*ber 6

我知道异步 Swift 任务不应该被阻塞(异步工作线程必须始终向前推进)。

这是对的。Swift 并发系统的基石是任务必须始终向前推进。

我可以使用 的主体withCheckedContinuation来启动线程,将延续句柄复制到该线程中,并在该线程完成时从该线程调用 continuation.resume 吗?

是的,这也是正确的,这正是延续的目的:

CheckedContinuation
同步和异步代码之间的接口机制,记录正确性违规。

延续的目的是让您能够将阻塞同步操作融入到async世界中。当你打电话时withCheckedContinuation,它

[s]暂停当前任务,然后使用当前任务的已检查延续调用给定的闭包。

该任务将无限期挂起,直到您恢复它,这允许其他任务同时取得进展。您获得的延续值是一个线程安全接口,指示您的阻塞操作已完成,并且原始任务应在下一个可用机会恢复。延续也是Sendable,这表明您可以在线程之间安全地传递它。任何线程都可以恢复任务,因此您甚至不一定需要回调同一线程上的延续。

SE-0300中的示例用法:将异步任务与同步代码连接起来的延续:

func operation() async -> OperationResult {
  // Suspend the current task, and pass its continuation into a closure
  // that executes immediately
  return await withUnsafeContinuation { continuation in
    // Invoke the synchronous callback-based API...
    beginOperation(completion: { result in
      // ...and resume the continuation when the callback is invoked
      continuation.resume(returning: result)
    }) 
  }
}
Run Code Online (Sandbox Code Playgroud)

请注意,这仅对于真正阻塞的任务是必要的,并且在完成它们所依赖的事情之前无法取得进一步的进展。这与执行主动计算的任务不同,后者恰好需要很长时间,因为这些任务至少正在积极进展。(但在聊天中,您澄清您的用例是前者。)