问题
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 pmapfrom here.- Modification of item 2: I removed
coroutineScopeand 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?
回答1:
Scopes are only indirectly involved in the differences you observed.
GlobalScope is a singleton that defines its own dispatcher, which is Dispatchers.Default. It is backed by a thread pool.
coroutineScope does not define its own dispatcher so you inherit it from the caller, in this case the one created by runBlocking. It uses the single thread it is called on.
If you replace coroutineScope with withContext(Dispatchers.Default), you'll get the same timings. This is in fact how you should write this (instead of GlobalScope) in order to get sane behavior in the face of possible failures of some of the concurrent tasks.
来源:https://stackoverflow.com/questions/55531464/kotlin-coroutinescope-is-slower-than-globalscope