首页 > 解决方案 > Kotlin 协程启动缓慢

问题描述

我一直在尝试对我拥有的应用程序进行一些性能评估,它是一个后端 Kotlin 应用程序,它只是拉入一些数据,进行一些数据转换并将其转储出来,没什么太花哨的。引起我注意的一件事是执行的最后一点,我们将最终数据转储到队列中,起初我注意到当我们启动应用程序时,最终的网络调用一开始需要很长时间,有时甚至超过一秒。通常我们在协程中运行这个网络调用来阻止最后一个调用阻塞一切,但是我开始尝试分别对协程和网络调用计时并得到一些奇怪的结果,从我所看到的协程可能需要永远启动/完成与网络通话相比。我完全有可能没有正确记录东西,但这是我的一般计时方法:

val coroutineTime - Instant.now().toEpochMillis()
GlobalScope.launch {
executionTime = measureTimeMillis { <--DO Message Sending -->}
totalTime = Instant.now().toEpochMillis() - coroutineTime 
// Log out execution Time and total time 
}

现在在这里我会看到类似

- totalTime = ~800ms 
- executionTime = ~150ms 

这些也不是一次性的,我有多个这样的进程同时进行(我认为最多 10 个线程),第一次总时间总是比实际的 executionTime/network 调用长得多。最终,在收到一打新消息后,开销会平静下来,这些时间将在大约 15 毫秒时变得相等,但是在协程启动时有近 700 毫秒的开销对我来说似乎很疯狂。

这是正常/预期的行为吗?我已经在一个单独的应用程序中对此进行了测试,并看到了类似但不太极端的结果,其中第一个协程将需要大约 70 毫秒才能启动,我正在努力寻找除 kotlin 用于 android 开发之外的任何其他此类讨论的示例.

标签: performancekotlinbackendkotlin-coroutines

解决方案


作为第一个注意事项,GlobalScope除非您真的知道自己在做什么,否则使用几乎从来都不是一个好主意。这就是为什么它被标记为精致的 API。相反,您应该使用适当关闭的范围(遵循启动此工作的任何组件的生命周期)。

现在,AFAIK,GlobalScope它在默认调度程序上运行,所以这可能是由于该默认线程池的冷启动。稍后,根据您拥有的并发协同程序的数量,使用此调度程序进行网络调用也可能是一个问题。更适合Disptachers.IO用于 IO 绑定工作(或自定义线程池)。

它仍然不能解释冷启动,但我会在调查之前先改变它。


推荐阅读