Kotlin:coroutineScope 比 GlobalScope 慢

Kotlin: coroutineScope is slower than GlobalScope

我正在学习协程,我遇到了以下令人惊讶的(对我来说)行为。我想要一张平行地图。我考虑了 4 种解决方案:

  1. 只是map,没有并行
  2. pmap 来自 here.
  3. 第 2 项的修改:我删除了 coroutineScope 并使用 GlobalScope
  4. Java 的 parallelStream.

代码:

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()) }
}

输出(没有求和):

No parallelism  time: 0.85726849
CoroutineScope  time: 0.827426385
GlobalScope     time: 0.145788785
ParallelStream  time: 0.161423263

如您所见,coroutineScope 几乎没有增益,而 GlobalScopeparallelStream 一样快。是什么原因?我能有一个具有相同速度增益的 coroutineScope 的所有优点的解决方案吗?

范围仅间接涉及您观察到的差异。

GlobalScope是一个单例,定义了自己的dispatcher,也就是Dispatchers.Default。它由线程池支持。

coroutineScope 没有定义自己的调度程序,因此您可以从调用者那里继承它,在本例中是由 runBlocking 创建的调度程序。它使用调用它的单个线程。

如果将 coroutineScope 替换为 withContext(Dispatchers.Default),您将获得相同的计时。实际上,这就是您应该编写此代码(而不是GlobalScope)的方式,以便在某些并发任务可能失败的情况下获得理智的行为。