kotlin 中的 actor 在不同线程上运行时如何工作?

pat*_*ues 2 concurrency actor kotlin kotlinx.coroutines

在kotlinlang.org 官方文档中的actor 示例中,一个 actor 被启动了 100 000 次,这只是增加了 actor 内部的一个计数器。然后,将获取请求发送给参与者,并在响应中发送带有正确金额 (100 000) 的计数器。

这是代码:

// The messages
sealed class CounterMsg
object IncCounter : CounterMsg() // one-way message to increment counter
class GetCounter(val response: CompletableDeferred<Int>) : CounterMsg() // a two-way message to get the counter

// The actor
fun CoroutineScope.counterActor() = actor<CounterMsg> { 
    var counter = 0 // actor state
    for (msg in channel) { // iterate over incoming messages
        when (msg) {
            is IncCounter -> counter++
            is GetCounter -> msg.response.complete(counter)
        }
    }
}

fun main() {
    runBlocking {
        val counterActor = counterActor()
        GlobalScope.massiveRun {
            counterActor.send(IncCounter) // run action 100000 times
        }
        val response = CompletableDeferred<Int>()
        counterActor.send(GetCounter(response))
        println("Counter = ${response.await()}")
        counterActor.close()
    }
}
Run Code Online (Sandbox Code Playgroud)

我无法理解如果 counterActor 协程在多个线程上执行会发生什么?如果协程在不同的线程上运行,那么参与者中的变量“计数器”可能容易受到竞争条件的影响,不是吗?

示例:一个线程运行一个协程,该协程在通道上接收,然后在另一个线程上,协程可以接收数据,并且它们都尝试同时更新计数器变量,从而错误地更新了变量。

在代码示例后面的文本中

Actor 本身在什么上下文中执行并不重要(为了正确性)。Actor 是一个协程,并且协程是按顺序执行的,因此将状态限制到特定的协程可以作为共享可变状态问题的解决方案

我很难理解这一点。有人可以详细说明这到底意味着什么,以及为什么竞争条件不会发生。当我运行该示例时,我看到所有协程都在同一主线程上运行,因此我无法证明我的竞争条件理论。

Ale*_*dov 5

“演员被发射了10万次”

否,actor在线时恰好启动了 1 次

val counterActor = counterActor()
Run Code Online (Sandbox Code Playgroud)

然后它从不同线程上并行工作的 100 个协程接收 100000 条消息。但它们不会counter直接增加变量,它们只是将消息添加到参与者的输入消息队列中。确实,这个操作,是在kotlinx中实现的。coroutines库,是线程安全的。