使用线程池作为调度程序时,delay() 会阻塞其协程吗?

delay() block its coroutine when using thread pool as the dispatcher?

玩转Kotlin协程,我的玩具代码结果一头雾水:

import kotlinx.coroutines.*
import java.util.concurrent.Executors

suspend fun task(sleepTime: Long) {
    println("start task in Thread ${Thread.currentThread()}")
    delay(sleepTime)
    //yield()
    println("end task with context in Thread ${Thread.currentThread()}")
}

println("start")
runBlocking {
    val handler = CoroutineExceptionHandler() { context, ex ->
        println("Caught: $context | ${ex.message}")
    }
    Executors.newFixedThreadPool(2)
        .asCoroutineDispatcher().use { dispatcher ->
            launch(dispatcher + handler) { task(100) }
            launch(Dispatchers.IO + handler) { task(1000) }
            println("called tasks ${Thread.currentThread()}")
        }
}
println("done")

输出:

start
start task in Thread Thread[pool-1-thread-1 @coroutine#2,5,main]
called tasks Thread[main @coroutine#1,5,main]
start task in Thread Thread[DefaultDispatcher-worker-2 @coroutine#3,5,main]
end task with context in Thread Thread[DefaultDispatcher-worker-2 @coroutine#3,5,main]
done

我的问题是为什么协程#1 不继续?如果我将 delay() 更改为 yield(),它会起作用:

start
start task in Thread Thread[pool-1-thread-1 @coroutine#2,5,main]
end task with context in Thread Thread[pool-1-thread-2 @coroutine#2,5,main]
called tasks Thread[main @coroutine#1,5,main]
start task in Thread Thread[DefaultDispatcher-worker-1 @coroutine#3,5,main]
end task with context in Thread Thread[DefaultDispatcher-worker-1 @coroutine#3,5,main]
done  

Closeable.use 执行其中的代码,然后关闭 Closable,在本例中是您的调度程序。由于启动的协程是 运行 异步的,use 不会等待它们完成,而是立即关闭调度程序,从而取消您的协程。有可能 yield() 发生得如此之快,以至于他们有时间在被取消之前完成。

如果您将 use 块移动到 runBlocking 块之外,然后它会等待它们完成。

fun main() {
    println("start")
    Executors.newFixedThreadPool(2)
        .asCoroutineDispatcher().use { dispatcher ->
            runBlocking {
                val handler = CoroutineExceptionHandler() { context, ex ->
                    println("Caught: $context | ${ex.message}")
                }
                launch(dispatcher + handler) { task(100) }
                launch(Dispatchers.IO + handler) { task(1000) }
                println("called tasks ${Thread.currentThread()}")
            }
        }
    println("done")
}