本文介绍了Kotlin:coroutineScope比GlobalScope慢的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm learning coroutines, and I encounter the following surprising (for me) behavior. I want to have a parallel map. I consider 4 solutions:

  1. map,没有并行性
  2. pmap来自此处.
  3. 第2项的修改:我删除了coroutineScope并使用了GlobalScope.
  4. Java的parallelStream.
  1. Just map, no parallelism
  2. pmap from here.
  3. Modification of item 2: I removed coroutineScope and use GlobalScope.
  4. Java's 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几乎没有增益,而使用GlobalScope时它的运行速度与parallelStream一样快.是什么原因?我可以找到一个具有coroutineScope的所有优点且速度增益相同的解决方案吗?

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?

推荐答案

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

Scopes are only indirectly involved in the differences you observed.

GlobalScope是一个单例,定义了自己的调度程序,即Dispatchers.Default.它由线程池支持.

GlobalScope is a singleton that defines its own dispatcher, which is Dispatchers.Default. It is backed by a thread pool.

coroutineScope没有定义其自己的调度程序,因此您可以从调用方继承它,在本例中为runBlocking创建的调度程序.它使用被调用的单线程.

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.

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

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.

这篇关于Kotlin:coroutineScope比GlobalScope慢的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-20 12:48