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) {
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}")
}