Kotlin的SequenceBuilder的线程安全性

时间:2019-03-28 09:49:32

标签: kotlin sequence kotlin-coroutines

鉴于Kotlin中存在一种用于标记序列和混合命令性代码的方法,lambda中的必需代码是否是sequence函数的自变量,因此必须是线程安全的?

例如,以下内容是否安全:

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的意思吗? (来自Is this implementation of takeWhileInclusive safe?

  2. 传递给sequence的lambda必须是线程安全的。 documentation为什么如此默认?而且tutorials仅涵盖非常简单的用例。

请详细说明哪种情况以及原因。

1 个答案:

答案 0 :(得分:1)

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

通常,如果您将序列传递给其他线程,以便协程每次都在另一个线程上恢复,则您需要确保的是,从挂起建立了先发关系恢复,从而提供整体效果,就好像协程已在单个线程上按顺序执行一样。