如何顺序运行 Kotlin 协程?

Ser*_*gey 5 android coroutine kotlin kotlin-coroutines kotlin-flow

我有一个CoroutineScopelog()函数的实例,如下所示:

private val scope = CoroutineScope(Dispatchers.IO)

fun log(message: String) = scope.launch { // launching a coroutine
    println("$message")
    TimeUnit.MILLISECONDS.sleep(100) // some blocking operation
}
Run Code Online (Sandbox Code Playgroud)

我使用这个测试代码来启动协程:

repeat(5) { item ->
    log("Log $item")
}
Run Code Online (Sandbox Code Playgroud)

log()函数可以从任何位置、任何位置调用Thread,但不能从协程调用。

经过几次测试后,我可以看到不连续的结果,如下所示:

Log 0
Log 2
Log 4
Log 1
Log 3
Run Code Online (Sandbox Code Playgroud)

打印日志的顺序可以不同。如果我理解正确的话,协程的执行并不能保证是顺序的。这意味着协程 foritem 2可以在协程 for 之前启动item 0

我希望协程针对每个项目按顺序启动,并且“某些阻塞操作”将按顺序执行,以始终实现下一个日志:

Log 0
Log 1
Log 2
Log 3
Log 4
Run Code Online (Sandbox Code Playgroud)

有没有办法让协同程序按顺序启动?或者也许还有其他方法可以实现我想要的?

预先感谢您的任何帮助!

Ten*_*r04 5

一种可能的策略是使用 Channel 按顺序加入已启动的作业。join您需要延迟启动作业,以便它们在被调用之前不会启动。trySend当通道容量无限时,总是会成功。您需要使用它trySend,以便可以从协程外部调用它。

private val lazyJobChannel = Channel<Job>(capacity = Channel.UNLIMITED).apply {
    scope.launch {
        consumeEach { it.join() }
    }
}

fun log(message: String) {
    lazyJobChannel.trySend(
        scope.launch(start = CoroutineStart.LAZY) {
            println("$message")
            TimeUnit.MILLISECONDS.sleep(100) // some blocking operation
        }
    )
}
Run Code Online (Sandbox Code Playgroud)