如何从另一个 class(在 Kotlin 中)退出 runBlocking 协程?

How do I exit a runBlocking coroutine from another class (in Kotlin)?

我试图让我的代码在发生某些事情时退出程序,例如用户退出命令。 这就是我 运行 我的程序:

fun main() = runBlocking {
    Bot().start()
}

不幸的是,运行 exitProcess(0)Thread.currentThread().interrupt()start() 之外调用时似乎没有做任何事情,这在我的用例中确实很不方便。

有什么解决办法吗?

runBlocking {
    val job = launch { start() }
    // Process input via other APIs here. When done:
    job.cancel()
}

(您可能需要研究 channels 以将 Cmd 对象传送到命令循环中,并在输入完成后关闭通道。)

我 运行 遇到与 runBlocking 相同的问题。

一点背景知识: 首先,我们必须使用 runBlocking 来弥合两者之间的差距库方法的接口实现和我们应用程序的组件只能在 MAIN/UI 线程上访问。在这个方法的实现中,我们必须同步 return 一个值,我们必须将我们的上下文从后台线程切换到 UI 线程以在 UI 线程上显式获取此信息。使用 runBlocking 从来不是我们的选择,但我们不得不这样做,因为别无选择。

问题: 这个 runBlocking 阻塞了另一个后台线程(在特定情况下)。它永无止境,它阻塞了我们应用程序的单独子进程中 运行 的后台线程。所以我查找了解决方案,并在 Github.

上找到了以下报告的问题

根据已报告问题的回答 here

When runBlocking machinery detects that it is cancelled it should not terminate its event loop until the coroutine inside it is still active.

然后他进一步解释说

This way, the termination of the coroutine is processed in the running event loop and the event loop terminates after that.

解决方案: 所以我想出了下面提到的对我有用的解决方案,你可以使用这个高阶函数.这是一个 100% 有效的解决方案,在生产中经过测试和验证。 注意:请不要在下面的代码片段中使用 withContext() 而不是 async(),因为它永远不会起作用。

fun <T> runBlockingWithTimeout(
    lifecycleScope: LifecycleCoroutineScope?,
    timeoutMillis: Long = 500L,
    block: () -> T
): T? {
    return lifecycleScope?.let {
        runBlocking {
            withTimeoutOrNull(timeMillis = timeoutMillis) {
                async(lifecycleScope.coroutineContext) {
                    block.invoke()
                }.await()
            }
        }
    }
}