kotlin - 为什么不使用 GlobalScope.launch?

标签 kotlin kotlin-coroutines jvm-languages

我读到强烈建议不要使用 Globalscopehere .

我有一个简单的用例。对于我收到的每条 kafka 消息(比如说一个 Id 列表),我必须拆分它并同时为每个 Id 调用一个休息服务,然后等待它完成并继续执行其他同步任务。该应用程序中没有其他东西需要协程。在这种情况下,我可以使用 Globalscope 吗?

注意:这不是安卓应用程序。它是一个运行在服务器端的 kafka 流处理器。它是一个在 Kubernetes 中运行的临时、无状态、容器化 (Docker) 应用程序(如果愿意,可以符合流行语)

最佳答案

您应该使用结构化并发适本地确定并发范围。如果您不这样做,您的协程可能会泄漏。在您的情况下,将它们限定为处理单个消息似乎是合适的。

这是一个例子:

/* I don't know Kafka, but let's pretend this function gets 
 * called when you receive a new message
 */
suspend fun onMessage(msg: Message) {
    val ids: List<Int> = msg.getIds()    

    val jobs = ids.map { id ->
        GlobalScope.launch { restService.post(id) }
    }

    jobs.joinAll()
}

如果对 restService.post(id) 的调用之一因异常而失败,该示例将立即重新抛出异常,并且所有尚未完成的作业都会泄漏。他们将继续执行(可能无限期地),如果他们失败了,你就不会知道了。

要解决这个问题,您需要确定协程的范围。这是没有泄漏的相同示例:

suspend fun onMessage(msg: Message) = coroutineScope {
    val ids: List<Int> = msg.getIds()    

    ids.forEach { id ->
        // launch is called on "this", which is the coroutineScope.
        launch { restService.post(id) }
    }
}

在这种情况下,如果对 restService.post(id) 的调用之一失败,则协程范围内的所有其他未完成的协程都将被取消。当你离开作用域时,你可以确定你没有泄露任何协程。

另外,因为 coroutineScope 会等到所有子协程完成,你可以放弃 jobs.joinAll() 调用。

旁注: 编写启动一些协程的函数时的约定是让调用者使用接收器参数决定协程范围。使用 onMessage 函数执行此操作可能如下所示:

fun CoroutineScope.onMessage(msg: Message): List<Job> {
    val ids: List<Int> = msg.getIds()    

    return ids.map { id ->
        // launch is called on "this", which is the coroutineScope.
        launch { restService.post(id) }
    }
}

关于kotlin - 为什么不使用 GlobalScope.launch?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54335365/

相关文章:

json - Moshi 将 null 反序列化为空列表

kotlin-coroutines - kotlin 协程 - 为什么 Thread.sleep 不暂停主线程启动?

kotlin - 如何在 Kotlin 中并发运行阻塞 Java 代码?

compilation - 从三地址代码到 JVM 字节码的代码生成

没有花括号的 Kotlin 类

android - Jetpack Compose TextField InputFilter 仅具有货币正则表达式输入

java - Google Play要求从受影响的应用中删除Install_referrer

android - 使用 JUnit5 assertThrows 和 MockWebServer 测试挂起函数的异常

java - Java 中的对象创建语法

clojure - 从 Lisp 学习 Clojure