如果你想在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.
具体调试方法点击标题