为何Actor内多Task可访问变量?并行运行会引发数据竞争吗?编译器为何未阻止?
Swift 并发疑问解答
针对你提出的三个问题,结合代码逐一说明:
1. 为何能从多个Task中访问变量?
你代码里的Actor1是普通class,不是Swift的actor类型(正确声明Actor需要用actor关键字,而非class)。普通类没有Actor特有的并发隔离机制,它的属性可以被任意Task直接访问,不管这些Task是不是在类的方法内部创建的。
2. 两个Task为何会并行运行?
performAsyncTasks是async方法,其中创建的两个Task会被系统调度到全局并发执行池中的不同线程上,自然会并行运行。如果Actor1是真正的actor类型,在其内部创建的Task默认会绑定到Actor的串行执行器,两个Task会串行执行而非并行——这正是Actor保证并发安全的核心机制之一。
3. 多次访问value是否会引发数据竞争?为何编译器未阻止该操作?
会引发数据竞争!value +=1不是原子操作,它包含「读取当前值→加1→写入新值」三个步骤。两个并行的Task同时执行这个操作时,会出现互相覆盖的情况,最终value的结果会小于预期的20000。
编译器没有阻止,是因为你用的是普通class,Swift的并发安全检查仅针对标记为actor、@MainActor或其他并发隔离类型的代码。普通class的属性访问默认不做并发安全校验,需要开发者自行通过锁、Actor或原子类型来保证线程安全。
修正后的示例代码(真正的Actor实现)
如果要实现无数据竞争的版本,需要把Actor1改成真正的Actor:
import SwiftUI @main struct MyApp: App { var body: some Scene { WindowGroup { ContentView().task { await Actor1().performAsyncTasks() } } } } // 用actor关键字声明,而非class actor Actor1 { var value = 0 func performAsyncTasks() async { // 两个Task会在Actor的串行执行器上运行,不会并行 Task { for i in 1...10_000 { print("In Task 1: \(i)") value += 1 } } Task { for i in 1...10_000 { print("In Task 2: \(i)") value += 1 } } } }
此时两个Task会串行执行,value最终会正确得到20000,也不会有数据竞争。
内容的提问来源于stack exchange,提问作者MaxFactorHub
相关产品推荐
相关产品推荐

