Actor 是一种并发编程模型,用于解决数据竞争和线程安全问题,任何时候保证只有一个线程可以访问 Actor 的内部状态,在结构上和 class 很相似,拥有初始化方法、普通方法、属性和下标、可以扩展满足协议等支持泛型,但是因为其保护内部状态免受数据竞争,所有他的方法和属性都默认是异步的。例如:
actor Person {
let name = ""
let age = 0
func play() {
print("name is \(name)")
}
}
如上代码在同一个隔离域中的成员可以自由相互访问,但是如果从外部持有 actor 并且访问这个特性,叫做跨 actor 调用,只能在异步函数中调用,函数也默认是异步的例如:
func foo() async {
let person = Person()
await person.play()
}
Actor 协议 如果想让 actor 类型的声明实现协议有两种方式: 1、让协议实现 Actor 协议
protocol Popuplar: Actor {
var popular: Bool {get}
}
actor Person {
private(set) var name = ""
private(set) var age = 0
}
extension Person: Popuplar {
var popular: Bool {
return age != 0
}
}
第二种方式定义异步协议方法,在语法上满足 可暂停 的特点如下:
protocol PopuplarAsync {
var popularAsync: Bool {get async}
}
actor Person {
private(set) var name = ""
private(set) var age = 0
}
extension Person: PopuplarAsync {
var popularAsync: Bool {
get async {
return age != 0
}
}
}
这样异步协议方法,普通 class 也可以实现,同步函数是异步函数的一个特例,如下:
protocol PopuplarAsync {
var popularAsync: Bool {get async}
}
class Student: PopuplarAsync {
private(set) var name = ""
private(set) var age = 0
var popularAsync: Bool {
return age != 0
}
}
说起 actor 也要提起 Sendable 它表达了类型的一种English,可以安全地在不同并发域之间传递,actor 隔离域提供了一个串行的执行环境,通过在域外使用 await 调用 actor 上的方法,然而总有一些情况是需要跨隔离域的,例如可以保证 PersonStruct的属性也是线程安全的
actor Person {
private(set) var name = ""
private(set) var age = 0
func visit(_ visitor: PersonStruct) -> PersonStruct {
var result = visitor
result.message = "Hello \(name)"
return result
}
}
struct PersonStruct: Sendable {
var message: String = ""
}