import kotlinx.coroutines.experimental.* import kotlinx.coroutines.experimental.channels.* class FixedPool(val workerCount: Int) { val channel = Channel() val jobs = mutableListOf() init { start() // start immediately } fun start() { repeat(workerCount) { i -> jobs.add(launch(CommonPool) { // or use your own coroutine context for (task in channel) { println("worker-$i starts ${task.name}") task() println("worker-$i finished ${task.name}") } }) } } fun execute(block: Task) { launch(Unconfined) { // seems safe to use Unconfined channel.send(block) } } suspend fun join() { for (j in jobs) j.join() } fun close() = channel.close() } class Task(val name: String, val time: Long) { operator fun invoke() { Thread.sleep(time) // block to simulate real operation } } runBlocking { val pool = FixedPool(2) pool.execute(Task("A", 1000)) pool.execute(Task("B", 2500)) pool.execute(Task("C", 1000)) pool.execute(Task("D", 1000)) pool.execute(Task("E", 1000)) // We must wait; in long running app maybe not needed pool.close() pool.join() } // Example how to run on desktop: // kotlinc-jvm -script coroutine-pool.kts -cp kotlinx-coroutines-core-0.22.2.jar -Xcoroutines=enable