performance - Kotlin: coroutineScope is slower than GlobalScope
问题描述
I'm learning coroutines, and I encounter the following surprising (for me) behavior. I want to have a parallel map. I consider 4 solutions:
- Just
map
, no parallelism pmap
from here.- Modification of item 2: I removed
coroutineScope
and useGlobalScope
. - Java's
parallelStream
.
The code:
import kotlinx.coroutines.*
import kotlin.streams.toList
import kotlin.system.measureNanoTime
inline fun printTime(msg: String, f: () -> Unit) =
println("${msg.padEnd(15)} time: ${measureNanoTime(f) / 1e9}")
suspend fun <T, U> List<T>.pmap(f: (T) -> U) = coroutineScope {
map { async { f(it) } }.map { it.await() }
}
suspend fun <T, U> List<T>.pmapGlob(f: (T) -> U) =
map { GlobalScope.async { f(it) } }.map { it.await() }
fun eval(i: Int) = (0 .. i).sumBy { it * it }
fun main() = runBlocking {
val list = (0..200).map { it * it * it }
printTime("No parallelism") { println(list.map(::eval).sum()) }
printTime("CoroutineScope") { println(list.pmap(::eval).sum()) }
printTime("GlobalScope") { println(list.pmapGlob(::eval).sum()) }
printTime("ParallelStream") { println(list.parallelStream().map(::eval).toList().sum()) }
}
Output (without sums):
No parallelism time: 0.85726849
CoroutineScope time: 0.827426385
GlobalScope time: 0.145788785
ParallelStream time: 0.161423263
As you can see, with coroutineScope
there is almost no gain, while with GlobalScope
it works as fast as parallelStream
. What is the reason? Can I have a solution which has all advantages of coroutineScope
with the same speed gain?
解决方案
范围仅间接涉及您观察到的差异。
GlobalScope
是一个单例,它定义了自己的调度程序,即Dispatchers.Default
. 它由线程池支持。
coroutineScope
没有定义它自己的调度器,所以你从调用者那里继承它,在这种情况下是由runBlocking
. 它使用调用它的单个线程。
如果您替换coroutineScope
为withContext(Dispatchers.Default)
,您将获得相同的时间。实际上,这就是您应该如何编写它(而不是GlobalScope
),以便在面对某些并发任务可能失败时获得理智的行为。
推荐阅读
- systemd - 如何知道 systemd 使用的是哪个切片定义
- text - xml中的TextInputLayout助手文本对齐/重力,以编程方式或通过使用自定义视图扩展TextInputLayout
- python - Pyenv 和活动环境的问题
- scala - 用于类验证的 Scala 反射测试
- hive - Hive ldap 身份验证组过滤器
- wordpress - 特定页面上的 Wordpress 加载功能
- html - CSS 动画过渡不适用于 Firefox
- javascript - 在用 React 加载 dom 内容后应用事件监听器
- java - 无法启动进入无限循环的 JBoss 服务器
- laravel - 为什么使用wire打开引导模式:单击并调度事件块滚动在管理菜单中