在Swift中使用await时,是否有必要在所有函数中始终使用async



我在Swift中有以下示例:

func call1() { call2() }
func call2() { call3() }
func call3() { call4() }
func call4() { call5() }
func call5() { print("finish") }

如果我想使call5((成为一个异步函数,是否必须将所有其他调用更改为async才能使call5(正常工作?

调用async函数需要匹配的await。要使其在同步上下文中工作,您需要将调用包装在任务中。

Task { await call5() }

这将在当前线程上生成一个并发任务。

以下是WWDC讨论,其中包含有关结构化并发的更多详细信息。https://developer.apple.com/videos/play/wwdc2021/10134/

您不必使它们都是async,但您可以考虑这样做。具体来说,通过使它们都异步,您可以享受两个好处:

  • call1的调用者现在可以知道整个序列何时完成,一直到call5

  • 如果call1的调用方被取消,结构化并发将确保取消被自动传播到call5

因此,您有两个选项:

  1. 保持call1-call4同步,但让call4Task { … }调用call5。如上所述,call1的呼叫者失去了知道call5何时完成的能力,并且您无法享受自动取消传播:

    func call1() { call2() }
    func call2() { call3() }
    func call3() { call4() }
    func call4() { Task { await call5() } }    // opts out of structured concurrency
    func call5() async { … }
    
  2. 您可以使它们全部异步,这样call1的调用者就可以知道整个序列何时完成,并享受自动取消传播。

    func call1() async { await call2() }
    func call2() async { await call3() }
    func call3() async { await call4() }
    func call4() async { await call5() }
    func call5() async { … }
    

简而言之,这两种方法都不一定是对的或错的:这取决于call5异步执行的操作。

此外,如果重构遗留代码库,您不必立即跳到选项2,而是可以从选项1开始,并随着时间的推移慢慢前进到选项2。请参阅WWDC 2021视频Swift并发:更新一个示例应用程序,了解如何随着时间的推移进行迁移。

最新更新