actor方法可以并发交互吗?

onm*_*133 0 actor async-await swift swift-concurrency

我正在观看有关使用 Swift Actor 保护可变状态的WWDC 视频

在一个示例中,他们展示了如何同时调用参与者方法

想象一下,我们有两个不同的并发任务试图同时获取相同的图像。第一个发现没有缓存条目,开始从服务器下载图像,然后被挂起,因为下载需要一段时间。当第一个任务是下载映像时,新映像可能会部署到同一 URL 下的服务器。现在,第二个并发任务尝试获取该 URL 下的图像。它还看不到缓存条目,因为第一次下载尚未完成,然后开始图像的第二次下载。下载完成时它也会被暂停。一段时间后,其中一个下载(假设这是第一个下载)将完成,并且其任务将在 Actor 上恢复执行。它填充缓存并返回猫的结果图像。现在第二个任务已完成下载,因此它被唤醒。它用它得到的悲伤猫的图像覆盖缓存中的相同条目。因此,即使缓存中已经填充了图像,我们现在也会为同一 URL 获取不同的图像。

在此输入图像描述

Actor 的整个想法不就是确保在任何给定时间只有一个调用者可以直接与 Actor 交互吗?

这是我的例子。在这里您可以看到“BEGIN增量”后面始终跟着“END增量”,并且后续调用increment必须等待

actor Counter {
    var count = 1

    func increment() {
        print("BEGIN increment")
        let url = URL(string: "https://google.com")!
        let data = try! Data(contentsOf: url)
        let string = String(data: data, encoding: .utf8) ?? ""
        print("END increment")
        count += 1
    }
}


struct ContentView: View {
    @State var counter = Counter()

    var body: some View {
        Button {
            Task.detached {
                await counter.increment()
            }
        } label: {
            Text("Click")
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Sco*_*son 6

视频中的问题是 actor 函数是异步的(一个async方法),await其中包含一个。Actor 保证一次只有一个 Actor 的同步函数运行。

苹果的警告是关于async向你的 Actor 添加方法。一个await在一个async是一个明确的指示符,表明您愿意让系统挂起当前线程并放弃参与者的上下文。这可以允许另一个任务声明该上下文并“重新输入”该函数。

这也意味着您在 之前得出的有关参与者状态的任何结论await在 之后的代码中都不能被认为是正确的await

在您的示例中,您的increment函数是同步的(未标记async)。因此,在您的函数中,没有必要暂停参与者上下文,从而允许另一个线程声明它。

换句话说,参与者的保证是使用 Swift Concurrency 实现的。async如果您使用 Swift Concurrency在 Actor 上实现方法,您可能会破坏这些保证,并打开一个可能会出现问题的裂缝。