Потокобезопасность Kotlin's SequenceBuilder - PullRequest
1 голос
/ 28 марта 2019

Учитывая, что в Kotlin существует способ записи последовательностей и смешивания императивного кода, требуется ли требуемый код в лямбда-выражении, являющийся аргументом функции 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 проявляет особую осторожность, так что лямбда, которая генерирует следующий элемент, всегда выполняется в одном и том же потоке. Функции сопрограмм / приостановки - это детали реализации, которые временно передают поток управления потребителю последовательности. Это то, о чем @RestrictSuspension? (С Безопасна ли эта реализация takeWhileInclusive? )

  2. Лямбда, переданная в sequence, должна быть поточно-ориентированной. Почему документация так молчалива по этому поводу? Также учебные пособия охватывают только очень простые варианты использования.

Пожалуйста, уточните, в чем дело и почему.

1 Ответ

1 голос
/ 28 марта 2019

Сопрограмма последовательности выполняется в вызывающем потоке, поэтому все вопросы безопасности потока являются обязанностью вызывающего.

В общем случае, если вы передаете последовательность другим потокам, чтобы сопрограмма возобновлялась в другом потоке каждый развсе, что вам нужно, это убедиться, что существует отношение случай-до , установленное от приостановки до возобновления, обеспечивая общий эффект, как если бы сопрограмма выполнялась последовательно в одном потоке.

...