在 Project Loom 的虚拟线程上运行 Kotlin 协程


如果你想在Kotlin中运行异步或非阻塞代码,你必须在CoroutineScope中运行它。
如果你要处理回调,你必须用suspendCancellableCoroutine将其转换为一个暂停的函数,这样你就可以在CoroutineScope中调用它。

@ExperimentalCoroutinesApi
suspend fun Blah.doSomethingSuspending() = suspendCancellableCoroutine { continuation ->
    this.onSuccess {
        continuation.resume(
            value = it,
            onCancellation = continuation::cancel
        )
    }

    this.onError {
        continuation.resumeWithException(exception = it)
    }

    this.onCancel {
        continuation.cancel(cause = it)
    }
}

对于阻塞代码,不幸的是,你只能使用Dispatchers.IO,它是一个巨大的线程池,每个派发仍然阻塞着一个线程:

withContext(Dispatchers.IO) {
    blockingFunction()
}


为此,让我们首在 VM 选项中启用 JDK19 的预览功能,这样可以使用虚拟线程。

接下来,我们需要定义我们的自定义 Dispatcher。如果你想自定义 Dispatcher 的工作方式,你可以扩展 ExecutorCoroutineDispatcher ...

val Dispatchers.LOOM: CoroutineDispatcher
    get() = object : ExecutorCoroutineDispatcher(), Executor {

        override val executor: Executor
            get() = this

        override fun close() {
            error("Cannot be invoked on Dispatchers.LOOM")
        }

        override fun dispatch(context: CoroutineContext, block: Runnable) {
            Thread.startVirtualThread(block)
        }

        override fun execute(command: Runnable) {
            Thread.startVirtualThread(command)
        }

        override fun toString() =
"Dispatchers.LOOM"

    }

或者我们可以创建一个 ExecutorService 并将其转换为 Dispatcher:

val Dispatchers.LOOM: CoroutineDispatcher
    get() = Executors.newVirtualThreadPerTaskExecutor().asCoroutineDispatcher()

使用我们自定义的 LOOM Dispatcher,我们现在能够将阻塞代码转换为非阻塞协程兼容代码,而不是受限于Dispatchers.IO.

具体调试方法点击标题