Kotlin 的 SequenceBuilder 的线程安全

Thread safety of Kotlin's SequenceBuilder

鉴于在 Kotlin 中存在一种标记序列和混合命令式代码的方法,作为 sequence 函数参数的 lambda 中所需的代码是否需要线程安全?

例如,以下是否安全:

var x: Int = 5

fun someSequence(): Sequence<Int> = sequence {
    while (true) {
        x++
        yield(x)
    }
}

fun main(args: Array<String>) {
    val seq = someSequence()
    seq.take(200).forEach(::println)
}

因为在构造序列时没有内在的并行性可以利用,所以我预计操作顺序不会有问题。但是,鉴于 sequence 是在协程的帮助下实现的:

public fun <T> sequence(@BuilderInference block: suspend SequenceScope<T>.() -> Unit): Sequence<T> = Sequence { iterator(block) }

public fun <T> iterator(@BuilderInference block: suspend SequenceScope<T>.() -> Unit): Iterator<T> {
    val iterator = SequenceBuilderIterator<T>()
    iterator.nextStep = block.createCoroutineUnintercepted(receiver = iterator, completion = iterator)
    return iterator
}

协程一般不固定到特定线程,我担心缓存读取。我设想了两种替代方案:

  1. sequence 函数特别小心,因此生成下一个元素的 lambda 总是在同一个线程中执行。协程/挂起函数是一个实现细节,它临时将控制流转移到序列的消费者。这就是 @RestrictSuspension 的意思吗? (来自

  2. 传递给 sequence 的 lambda 必须是线程安全的。为什么 documentation so tacit about this? Also tutorials 只涵盖非常简单的用例。

请详细说明是哪种情况,为什么。

序列的协程在调用线程上执行,因此所有线程安全问题都是调用者的责任。

一般来说,如果你将序列传递给其他线程,让协程每次都在另一个线程上恢复,你只需要确保有一个happens-before从挂起到恢复建立的关系,提供整体效果,就好像协程一直在单线程上顺序执行。