两个协程同时调用一个函数两次

Invoking a function twice by two coroutines simultaneously

如何运行一个函数同时被两个协程执行两次? 我试过这段代码:

import kotlinx.coroutines.*

fun main() = runBlocking<Unit> {
    launch {
        calculate("first")
    }
    launch {
        calculate("second")
    }
}

fun calculate(name: String) {
    var value = 0
    for (x in 1..1_000){
        value += 1
        if(x % 100 == 0){
            println("calculating $x for $name")
        }
    }
}

但是第二个协程要等到第一个协程离开函数,运行它!

我该怎么办?

协程调度程序无法在代码中的任何位置从一个协程跳转到另一个协程(就像线程那样)。协程中的所有非挂起(阻塞)代码被立即调用,并且只有当协程被暂停时,dispatcher才能让另一个协程在同一个线程中完成它的工作。

这意味着你的函数 calculate 必须 暂停 你的协程在某些时候 - 对于你的情况,你应该调用暂停函数 yield(),例如,在循环的每次迭代之后。这个函数产生一个协程调度线程给其他协程到 运行.

suspend fun calculate(name: String) {
    var value = 0
    for (x in 1..1_000){
        value += 1
        if(x % 100 == 0){
            println("calculating $x for $name")
        }
        yield()
    }
}

runBlocking 使用事件循环作为协程调度程序的默认值。对于事件循环,只有一个协程可以同时在事件线程上运行。

您可以指定任何其他使用线程池的调度程序,例如Dispatchers.Default,到 运行 同时协程。

fun main() = runBlocking<Unit>(Dispatchers.Default) {
    launch {
        calculate("first")
    }
    launch {
        calculate("second")
    }
}

由于您要并行化的代码不可暂停,因此您没有充分的理由使用协程。您基本上是在使用整个协程机制来将作业发送到线程池,并强制调用者建立协程范围。

相反,您可以将任务提交给 IO 调度程序下的执行程序:

fun main() {
    Dispatchers.IO.asExecutor().apply {
        execute { calculate("first") }
        execute { calculate("second") }
    }
}