1.前言
- 数据竞争使得并发更加困难。代码很琐碎、很难调试
- async task不能捕获mutable变量
2.Actors
- actors为共享的mutable变量提供synchornization
- actors的属性是和其他代码分离开的
- 要想访问actors的属性,只能通过actors
- actors的访问机制会保证没有数据竞争
1 | struct Counter { |
3. Actor reentrancy
actor中在运行一段可能会导致任务suspend的代码(await)时,可能会导致actor的状态变化,此时需要在resumption时检查
actor ImageDownloader { private var cache: [URL: Image] = [:] func image(from url: URL) async throws -> Image? { if let cached = cache[url] { return cached } let image = try await downloadImage(from: url) // Potential bug: `cache` may have changed. cache[url] = image return image } } <!--1--> *
4.Actor Isolation
actor isolation 是actor类型的基本原则
actor也可以遵循协议
actor LibraryAccount { let idNumber: Int var booksOnLoan: [Book] = [] } <!--2-->
nonisolation 可以在actor外面运行
extension LibraryAccount: Hashable { nonisolated func hash(into hasher: inout Hasher) { hasher.combine(idNumber) // 只能访问imutable变量,不能访问mutable变量(例:bookOnloan) } } <!--3-->
detached task中的闭包不是isolated
extension LibraryAccount { func readSome(_ book: Book) -> Int { ... } func read() -> Int { ... } func readLater() { asyncDetached { await read() // 不是isolated,因此要访问read必须加上await } } }
5.Sendable
- 用来解决数据冲突
- actor中使用值类型是安全的
- actor中使用引用类型(class)是不安全的
- 此时可以使用
@Sendable
- 此时可以使用
- Sendable可以在不同的actor中共享
- 很多类型可以是sendable
- 值类型
- Actor类型
- immutable class(类他本身及子类只能包含imutable属性)
- internally-synchornized class (类内只有同步操作)
- @Sendable函数
- Sendable类型不会有数据竞争问题
- swift会禁止非Sendable类型共享
- 让自定义类型遵循Sendable协议,swift会自动检查
- @Sendable函数
- 也遵循Sendable协议
- 对闭包有一些限制
- 不能捕获mutable变量
- 捕获的也要是Sendable类型
- 同步的闭包,不能是actor-isolated。因为可能会使代码在actor外运行
6.Main Actor
- 代表主线程的actor
- 所有的异步操作都是在主线程完成
- 主线程的代码和数据分散的到处都是
- swift会自动保证代码运行在主线程,不再需要手动确保
- 类型也可以设为mainActor