Rob*_*Rob 12

一个区别是,一个采用同步闭包,而另一个则使用async闭包。具体来说,run采用同步闭包(即 is bodynot async

public static func run<T>(resultType: T.Type = T.self, body: @MainActor @Sendable () throws -> T) async rethrows -> T where T : Sendable
Run Code Online (Sandbox Code Playgroud)

这非常适合这样的场景:您在其他角色上,但想要运行一系列三个方法,所有这些方法都与主要角色隔离,但想要通过单个上下文切换(而不是三个)来完成。

但是,在 中Task.initoperationis async,这使其成为稍微更灵活的机制:

public init(priority: TaskPriority? = nil, operation: @escaping @Sendable () async -> Success)
Run Code Online (Sandbox Code Playgroud)

因此,为了说明差异,请考虑:

Task { @MainActor in
    statusText = "Fetching"
    await viewModel.fetchData()
    statusText = "Done"
}
Run Code Online (Sandbox Code Playgroud)

但你不能await在以下范围内MainActor.run

Task {
    await MainActor.run {            // Cannot pass function of type '@Sendable () async -> ()' to parameter expecting synchronous function type
        statusText = "Fetching"
        await viewModel.fetchData()
        statusText = "Done"
    }
}
Run Code Online (Sandbox Code Playgroud)

您必须Task在里面再插入一个。(!)

Task {
    await MainActor.run {
        Task {
            statusText = "Fetching"
            await viewModel.fetchData()
            statusText = "Done"
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

实际上我很少使用这两种模式,但这是它们之间的一个区别。

  • FWIW,我发现如果在正确的参与者上定义了方法或属性,则很大程度上会使上述模式变得毫无意义。恕我直言,负担应该在定义点,而不是在调用点。在某些边缘情况下,这些是有用的(例如,减少上下文切换的数量),但通常只是代码味道。 (3认同)