我有一个像这样声明的演员协议:
protocol MyActorProtocol: Actor {
func foo()
}
有一个符合协议的演员:
actor MyImplementation1: MyActorProtocol {
func foo() {}
}
现在我需要添加代理:
actor MyImplementation1Proxy: MyActorProtocol {
let impl: MyActorProtocol
init(impl: MyActorProtocol) {
self.impl = impl
}
func foo() {
// Error-1: Call to actor-isolated instance method 'foo()' in a synchronous actor-isolated context
// impl.foo()
// Error-2. 'await' in a function that does not support concurrency
// await impl.foo()
// Success-3. only this passes the compiler check
Task { await impl.foo() }
}
}
我想了解以下几点:
nonisolated
关键字的情况下声明非异步方法?Error-1
?MyImplementation1Proxy
也符合MyActorProtocol
,并且MyImplementation1.foo
必须在Task
中调用(无论出于何种原因),那么感觉MyImplementation1.foo
是“某种异步”,所以MyImplementation1Proxy.foo
应该有这个“也是一种异步上下文”,那么为什么我有 Error-2
?Error-2
看来,该方法只是“非异步”,但是当我尝试引入非参与者实现时,得到了Call to actor-isolated instance method 'foo()' in a synchronous nonisolated context
,这是公平的,但再次引出了问题1:class MyImplementation2 {
let impl: MyActorProtocol
init(impl: MyActorProtocol) {
self.impl = impl
}
func bar() {
impl.foo()
}
}
提前致谢。
为什么 Actor 协议可以有非异步方法 声明,没有显式的非隔离关键字?
Actor
方法本质上是同步的。然而,这些同步方法可以是一些更广泛的async
例程的一部分。 Actor
隔离它们的方法,以保护它们共享的可变状态不被其他一些并发例程访问。
突变只能通过
Actor
内的孤立方法发生。无法从 Actor
之外的同步上下文调用隔离方法。
actor MyActor {
var state = 0
func foo() {
state += 1
}
}
let actor = MyActor()
actor.foo() // Error: Call to actor-isolated instance method 'foo()' in a synchronous nonisolated context
如果您想从
Actor
之外的同步上下文调用方法,则需要将其设置为 nonisolated
。但这意味着不会发生突变,因为 Actor
旨在保护其状态。
actor MyActor {
var state = 0
nonisolated func foo() {
state += 1 // Error: Actor-isolated property 'state' can not be mutated from a non-isolated context
}
}
let actor = MyActor()
actor.foo()
仅当我们不改变 Nonisolated
的状态时,
Actor
才有效
actor MyActor {
nonisolated func foo() {
print("I'm not mutating here..")
}
}
let actor = MyActor()
actor.foo()
总而言之,Actor 方法本质上并不是异步的,但如果您想从外部调用它们并仍然遵守隔离规则,则需要从异步上下文中完成。另一方面,
nonisolated
方法必须是不可变的,因此它们在设计上遵循隔离规则,并且可以从同步上下文安全地调用它们。