Multithreading usando Kotlin Coroutines

Estoy experimentando con Kotlin Coroutines y tengo el siguiente código:

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

Este es mi resultado:

 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 

Según la respuesta de Roman Elizarov a otra pregunta relacionada con corutinas:

"El lanzamiento solo crea nueva coroutine, mientras que CommonPool distribuye coroutines a ForkJoinPool.commonPool () que sí utiliza varios hilos y, por lo tanto, se ejecuta en varias CPU en este ejemplo".

De acuerdo con la documentation de Java 8:

"Para las aplicaciones que requieren pools separados o personalizados, un ForkJoinPool puede buildse con un nivel de paralelismo objective dado, por defecto, igual al número de procesadores disponibles".

¿Por qué solo se usan 3 hilos de trabajo? Existen los mismos 3 hilos de trabajo incluso cuando aumente el número de tareas asincrónicas a 1000+.

Mi configuration: Mac / High Sierra con CPU de doble núcleo (con Hyper-threading , por lo tanto, 4 núcleos visibles), Kotlin 1.2, kotlinx-coroutines-core: 0.19.3 y JVM 1.8

Si observa la implementación de CommonPool , verá que está trabajando en java.util.concurrent.ForkJoinPool o en un grupo de subprocesss con el siguiente tamaño:

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

Con 4 procesadores disponibles, esto dará como resultado 3 que responde por qué ve 3 subprocesss de trabajo.

El tamaño de ForkJoinPool se puede determinar de la siguiente manera (será el mismo):

 ForkJoinPool.commonPool().parallelism