Swift 从同步上下文调用主要参与者的异步函数

Anu*_*ole 6 async-await swift

我试图理解为什么下面的代码会抛出断言。我想做的是asyncFunc()从调用站点调用主线程/主要参与者。我不想用 asyncFunc 来装饰,@MainActor因为我希望该函数与线程无关。

func asyncFunc() async -> String? {
     dispatchPrecondition(condition: .onQueue(.main))
     return "abc"
}

func callSite() {
     Task { @MainActor in
          await asyncFunc()
     }
}
Run Code Online (Sandbox Code Playgroud)

我的理解是,Task { @MainActor ...}将在 MainActor/主线程上执行以下所有代码。

Sou*_*unt 3

目前,Swift 中的 Actor 是可重入的,如提案中所述:

参与者隔离的函数是可重入的。当参与者隔离函数挂起时,重入允许在原始参与者隔离函数恢复之前在参与者上执行其他工作,我们将其称为交错。可重入消除了死锁的根源,其中两个参与者相互依赖,可以通过不必要地阻止参与者的工作来提高整体性能,并为更好地调度(例如)更高优先级的任务提供机会。

因此,您的任务asyncFunc不会继续运行MainActor,因为它将阻止参与者处理其他高优先级任务。要解决此问题,您可以尝试以下两种方法:

  1. 使您的函数同步,以便它将运行在MainActor
func syncFunc() -> String? {
     dispatchPrecondition(condition: .onQueue(.main))
     return "abc"
}

func callSite() {
     Task { @MainActor in
         syncFunc()
     }
}
Run Code Online (Sandbox Code Playgroud)
  1. 或者显式标记要运行的异步函数MainActor
@MainActor
func asyncFunc() async -> String? {
     dispatchPrecondition(condition: .onQueue(.main))
     return "abc"
}

func callSite() {
     Task {
          await asyncFunc()
     }
}
Run Code Online (Sandbox Code Playgroud)

请注意,同样的重入规则也适用于此,asyncFunc(ie dispatchPrecondition) 中的同步调用将在 上执行MainActor,而内部的任何异步调用asyncFunc都不会在 上调用MainActor