在同步参与者隔离上下文中调用参与者隔离实例方法

问题描述 投票:0回答:1

我有一个像这样声明的演员协议:

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() }
    }
}

我想了解以下几点:

  1. 为什么 Actor 协议可以在没有显式
    nonisolated
    关键字的情况下声明非异步方法?
  2. 假设可以有非异步方法,那么为什么我的代码中会有
    Error-1
  3. 鉴于
    MyImplementation1Proxy
    也符合
    MyActorProtocol
    ,并且
    MyImplementation1.foo
    必须在
    Task
    中调用(无论出于何种原因),那么感觉
    MyImplementation1.foo
    是“某种异步”,所以
    MyImplementation1Proxy.foo
    应该有这个“也是一种异步上下文”,那么为什么我有
    Error-2
  4. 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()
   }
}

提前致谢。

swift async-await structured-concurrency
1个回答
0
投票

为什么 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
方法必须是不可变的,因此它们在设计上遵循隔离规则,并且可以从同步上下文安全地调用它们。

© www.soinside.com 2019 - 2024. All rights reserved.