Kotlin协程是否提供任何“之前发生”的保证?
例如,在这种情况下,在写入mutableVar
和随后在(可能)其他线程上读取之间是否存在“happens-before”保证:
suspend fun doSomething() {
var mutableVar = 0
withContext(Dispatchers.IO) {
mutableVar = 1
}
System.out.println("value: $mutableVar")
}
编辑:
也许额外的例子会更好地澄清这个问题,因为它更像Kotlin(除了可变性)。这段代码是线程安全的吗:
suspend fun doSomething() {
var data = withContext(Dispatchers.IO) {
Data(1)
}
System.out.println("value: ${data.data}")
}
private data class Data(var data: Int)
2条答案
按热度按时间atmip9wb1#
你写的代码有三种对共享状态的访问:
这三个访问是严格按顺序排序的,它们之间没有并发性,你可以放心,Kotlin的基础设施在切换到
IO
线程池并返回到调用协程时会负责建立一个 happens-before 边缘。下面是一个可能看起来更有说服力的等效示例:
由于
delay
是一个可挂起的函数,并且由于我们使用的是由线程池支持的Default
分派器,因此第1、2和3行可以分别在不同的线程上执行。因此,你关于 happen-before 保证的问题同样适用于这个例子。另一方面,在这种情况下,(我希望)这段代码的行为与顺序执行的原则是一致的,这是完全显而易见的。KotlinCoroutines的主要作者Roman Elizarov在blog post中提出了同样的观点。相关报价:
尽管Kotlin中的协程可以在多个线程上执行,但从可变状态的Angular 来看,它就像一个线程。同一协程中没有两个动作可以并发。
oxf4rvwz2#
Kotlin中的协程确实提供了保证之前的发生。
规则是:在协程中,suspend函数调用之前的代码发生在suspend调用之后的代码**之前。
你应该把协程看作是常规线程:
尽管Kotlin中的协程可以在多个线程上执行,但从可变状态的Angular 来看,它就像一个线程。同一协程中没有两个动作可以并发。
来源:https://proandroiddev.com/what-is-concurrent-access-to-mutable-state-f386e5cb8292
回到代码示例。在lambda函数体中捕获var并不理想,特别是当lambda是一个协程时。事实上
将可变变量(var)捕获到这样的块的作用域中几乎总是一个错误
(来自KT-15514的声明)
lambda之前的代码不会在内部代码之前发生。
参见https://youtrack.jetbrains.com/issue/KT-15514