COROUTINES

CoroutineScope

Allows objects to provide scope for coroutines

async & launch become instance methods

they provide a default context

To start coroutine scope you can:

Use GlobalScope that has empty coroutine context.

Implement CoroutineScope interface. Create a scope from a context:

with(CoroutineScope(context = context)){}))

Coroutine builders

- launch

Launches new coroutine without blocking current thread and returns a reference to

the coroutine as a Job.

(launch is when you want to fire and forget)

- runBlocking

Runs new coroutine and blocks current theread interruptible until its completion.

- async

Creates new coroutine and returns its future result as an implementation of Deferred.

async doesn't throw until await() o join()

(async is when we wnat to run something, then await the resul)

- withContext

Change a coroutine context for some block.

Reference

Coroutine dispatchers

The things wihich runs and schedules coroutines

- Dispatchers.Default

Different thread(if possible) it is backerd by a shared pool of threads on JVM.

Uses cpuCount threads(core)

Elastic thread executor

Default dispatcher

- Dispatchers.Main

Platform specific main thread (if exists).

Allows running coroutines on UI main thread

- Dispatchers.IO

Thread designed for offloadin blocking IO tasks to a shared pool of threads.

IO dispatcher uses Dispatchers.Default

Designed for blocking I/O tasks

- Dispatchers.Unconfined

Always uses first available thread (most performant dispatcher).

- newSingleThreadContext

Creates a new coroutine execution context using a single thread with built-in yield support

Reference Reference

Resume with code

import kotlinx.coroutines.* import java.util.concurrent.ExecutorService import java.util.concurrent.Executors fun main(args: Array<String>) { exampleWithContext() } suspend fun printlnDelayed(message: String) { // Complex calculation delay(1000) println(message) } suspend fun calculateHardThings(startNum: Int): Int { delay(1000) return startNum * 10 } fun exampleBlocking() = runBlocking { println("one") printlnDelayed("two") println("three") } // Running on another thread but still blocking the main thread fun exampleBlockingDispatcher(){ runBlocking(Dispatchers.Default) { println("one - from thread ${Thread.currentThread().name}") printlnDelayed("two - from thread ${Thread.currentThread().name}") } // Outside of runBlocking to show that it's running in the blocked main thread println("three - from thread ${Thread.currentThread().name}") // It still runs only after the runBlocking is fully executed. } fun exampleLaunchGlobal() = runBlocking { println("one - from thread ${Thread.currentThread().name}") GlobalScope.launch { printlnDelayed("two - from thread ${Thread.currentThread().name}") } println("three - from thread ${Thread.currentThread().name}") delay(3000) } fun exampleLaunchGlobalWaiting() = runBlocking { println("one - from thread ${Thread.currentThread().name}") val job = GlobalScope.launch { printlnDelayed("two - from thread ${Thread.currentThread().name}") } println("three - from thread ${Thread.currentThread().name}") job.join() } fun exampleLaunchCoroutineScope() = runBlocking { println("one - from thread ${Thread.currentThread().name}") val customDispatcher = Executors.newFixedThreadPool(2).asCoroutineDispatcher() launch(customDispatcher) { printlnDelayed("two - from thread ${Thread.currentThread().name}") } println("three - from thread ${Thread.currentThread().name}") (customDispatcher.executor as ExecutorService).shutdown() } fun exampleAsyncAwait() = runBlocking { val startTime = System.currentTimeMillis() val deferred1 = async { calculateHardThings(10) } val deferred2 = async { calculateHardThings(20) } val deferred3 = async { calculateHardThings(30) } val sum = deferred1.await() + deferred2.await() + deferred3.await() println("async/await result = $sum") val endTime = System.currentTimeMillis() println("Time taken: ${endTime - startTime}") } fun exampleWithContext() = runBlocking { val startTime = System.currentTimeMillis() val result1 = withContext(Dispatchers.Default) { calculateHardThings(10) } val result2 = withContext(Dispatchers.Default) { calculateHardThings(20) } val result3 = withContext(Dispatchers.Default) { calculateHardThings(30) } val sum = result1 + result2 + result3 println("async/await result = $sum") val endTime = System.currentTimeMillis() println("Time taken: ${endTime - startTime}") }