Gis*_*453 2 kotlin kotlin-coroutines
什么是协程作用域
runBlocking {
// some code here
}
Run Code Online (Sandbox Code Playgroud)
在 Kotlin 协程中?
它对于调用它的类来说是本地的,并且当类被垃圾收集时,协程也会被垃圾收集吗?或者如果它仍在运行,会导致内存泄漏吗?
与launch或async不同,runBlocking
它是一个非常特殊的协程构建器,因为它应该在顶层使用。因此它不在作用域内CoroutineScope
运行(如您所见,没有接收器)。它更应该成为结构化并发的“根”。
runBlocking
实际上为您提供了一个范围,因此您可以在其中启动“子”协程。真正重要的是,runBlocking
将等待您在该范围内启动的所有协程(子协程)完成后再返回。
如果协程挂起,您无法真正从外部取消runBlocking
协程本身(就像您通过取消launch
or的范围所做的async
那样),因为它不是异步任务 - 它正在阻塞线程。您可以中断运行它的线程,或者也可以跟踪嵌套协程并显式取消它们以runBlocking
完成。
runBlocking
仅当所有子协程完成(或取消)后,调用才会返回。(从内部)抛出异常也会取消所有子协程并重新抛出runBlocking
该异常。所以这也是一种runBlocking
从内部“取消”的方式。
它对于调用它的类来说是本地的,并且当类被垃圾收集时,协程也会被垃圾收集吗?或者如果它仍在运行,会导致内存泄漏吗?
你可以看到runBlocking
任何阻塞函数,比如Thread.sleep
,没有更多的魔法了。就像Thread.sleep
,runBlocking
可以从任何函数调用,甚至是顶级函数,在这种情况下,不会涉及任何类实例。
让我们假设类中的一个方法调用runBlocking
,并且内部的任何内容runBlocking
都会挂起很长时间(例如长时间睡眠)。然后,无论谁调用此方法,都将保留对该实例的引用,直到该方法返回或失败,因此该实例无论如何都不会被垃圾收集。在这种情况下,调用者将挂起,阻塞它正在运行的任何线程——这就是可能发生泄漏的地方。
runblocking
如果您在 Spring MVC 控制器的方法中使用,Spring 可能会为每个方法创建线程,如果有任何内容挂在内部runBlocking
,您可能会泄漏线程。相反,您可以使用 Spring WebFlux,它允许您直接在 Spring 控制器中使用suspend
函数(并添加请求超时以自动取消挂起的内容)。
使用runBlocking
内部回调也可能很危险。您正在使用的假设的基于回调的 API 可能正在使用线程池来回调您,如果runBlocking
挂起,则可能会阻塞该线程池。
如果该 API 支持背压,那么阻塞可能是可以的。API 还可以以非阻塞方式支持这一点(例如 JDK11 的websocket 侦听器,它允许您CompletableStage
从回调中返回 a),在这种情况下,您应该构建 aFuture
而不是阻塞。
如果 API 不支持背压,您可能不得不在其中创建自定义的CoroutineScope
and launch
-ing 协程来处理回调(而不是runBlocking
)。当您不再使用基于回调的 API 时,您必须手动取消该范围。
归档时间: |
|
查看次数: |
1545 次 |
最近记录: |