使用Kotlin协同程序进行多线程处理

时间:2017-12-01 10:47:21

标签: multithreading jvm kotlin kotlinx.coroutines

我正在尝试使用Kotlin Coroutines并拥有以下代码:

fun main(args: Array<String>) = runBlocking {
    val cores = Runtime.getRuntime().availableProcessors()
    println("number of cores: $cores")

    val jobs = List(10) {
        async(CommonPool) {
            delay(100)
            println("async #$it on thread ${Thread.currentThread().name}")
        }
    }
    jobs.forEach { it.join() }
}

这是我的输出:

number of cores: 4
async number:0 on thread ForkJoinPool.commonPool-worker-2
async number:2 on thread ForkJoinPool.commonPool-worker-3
async number:3 on thread ForkJoinPool.commonPool-worker-3
async number:4 on thread ForkJoinPool.commonPool-worker-3
async number:5 on thread ForkJoinPool.commonPool-worker-3
async number:1 on thread ForkJoinPool.commonPool-worker-1
async number:7 on thread ForkJoinPool.commonPool-worker-3
async number:6 on thread ForkJoinPool.commonPool-worker-2
async number:9 on thread ForkJoinPool.commonPool-worker-3
async number:8 on thread ForkJoinPool.commonPool-worker-1

根据Roman Elizarov的answer与另一个与coroutines相关的问题:

  

“启动只会创建新的协程,而CommonPool会调度   对使用多个的ForkJoinPool.commonPool()的协同程序   在这个例子中,线程因此在多个CPU上执行。“

根据Java 8 documentation

  

“对于需要单独或自定义池的应用程序,a   ForkJoinPool可以用给定的目标并行度级构建;   默认情况下,等于可用处理器的数量。“

为什么只使用3个工作线程?即使我将异步任务的数量增加到1000 +,也有相同的3个工作线程。

我的配置: Mac / High Sierra具有双核cpu(带Hyper-threading,因此有4个可见核心),Kotlin 1.2,kotlinx-coroutines-core:0.19.3和JVM 1.8

2 个答案:

答案 0 :(得分:4)

如果查看CommonPool的实现,您会发现它正在java.util.concurrent.ForkJoinPool或具有以下大小的线程池:

(Runtime.getRuntime().availableProcessors() - 1).coerceAtLeast(1)

使用4个可用的处理器,这将导致3回答为什么你看到3个工作线程的原因。

ForkJoinPool - 大小可以如下确定(将是相同的):

ForkJoinPool.commonPool().parallelism

如果您使用的是coroutines版本&gt; = 1.0

,请参阅this answer

答案 1 :(得分:1)

从Coroutines 1.0开始,由于CommonPool现在将被Dispatchers.Default替换,因此代码看起来会稍有不同:

fun main(args: Array<String>) = runBlocking {
    val cores = Runtime.getRuntime().availableProcessors()
    println("number of cores: $cores")

    val jobs = List(10) {
        async(Dispatchers.Default) {
            delay(100)
            println("async #$it on thread ${Thread.currentThread().name}")
        }
    }
    jobs.forEach { it.join() }
}

此外,您现在将获得以下内容:

  

它由JVM上的共享线程池支持。默认情况下,此调度程序使用的最大线程数等于CPU内核数,但至少为两个。