actor

50 阅读2分钟

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 = ""
}