Первое, что следует отметить, это то, что результат будет другим с runBlocking
.
fun main() = runBlocking { ...
С runBlocking
сопрограмма будет ограничена событием l oop.
Затем, вызвав continuation.resume
, созданный поток передаст результат сопрограмме, которая будет выполнена основным потоком. И 4
и 5 6
будут регистрироваться одновременно. Это может быть 4 5 6
, 5 4 6
или 5 6 4
.
suspend fun main
не определяет Dispatcher
, поэтому, когда Continuation
возобновляется, он использует текущая тема. Нет ограничений по нитям.
https://github.com/Kotlin/kotlinx.coroutines/issues/1591#issuecomment -537421694
Так что это похоже на запуск сопрограммы в Unconfined
.
При возобновлении сопрограммы могут произойти две вещи. Давайте посмотрим на определение suspendCoroutine
.
public suspend inline fun <T> suspendCoroutine(crossinline block: (Continuation<T>) -> Unit): T =
suspendCoroutineUninterceptedOrReturn { c: Continuation<T> ->
val safe = SafeContinuation(c.intercepted())
block(safe)
safe.getOrThrow()
}
getOrThrow
в основном и reusme
в новом потоке будут участвовать в гонке для установки поля result
в SafeContinuation
.
Если выиграет getOrThrow
, сопрограмма будет приостановлена. Новый поток выполнит остальную часть сопрограммы самостоятельно (потому что она не ограничена). Он может регистрировать 4
только после запуска продолжения.
Т.е. результат будет 5 6 4
.
Если resume
выиграет, getOrThrow
вернет фактический результат, и сопрограмма не будет приостановлено. Новый поток не пытается запустить продолжение, потому что основной поток продолжит выполнение остальной части сопрограммы.
Снова, 4
и 5 6
будут зарегистрированы одновременно.
Вы можете сделайте resume
победой sleep
в главном после запуска нового потока.
Если вы посмотрели код и поняли предыдущие параграфы. Я надеюсь, теперь очевидно, почему результат всегда 4 5 6, когда вы resume
синхронно внутри suspendCoroutine
. Поскольку resume
всегда вызывается раньше getOrThrow
.
Я думаю, что можно умело использовать Kotlin сопрограммы, не понимая ничего из вышеперечисленного. Просто используйте ограниченные сопрограммы и покончите с этим.