Coroutines
First
Me yesterday
Me this morning
Resources
Back to the basics
What is a function ?
A sequence of instructions that takes inputs and gives us outputs
fun makeASandwich(): Sandwich{
val bread = Bread(seed = oat)
val sauce = "harissa" + "mayo"
return Sandwich(bread, sauce, "beef")
}
fun goToRestaurant(): Boolean?{
throw YouAreBrokeDude()
return null
}
fun eat(){
try{
goToRestaurant()
}
catch(error: YouAreBrokeDude){
makeASandwich()
}
}
eat()
A thread describe in which context this sequence of instructions should be executed
//Thread 1
println("Hello world")
var x = 3
x *= x
println("The result is $x")
//Thread 2
println("Hello world from another thread")
var x = 5
x *= x
println("The result is $x from the other thread")
Why do we care anyway, can't we run everything in the same thread ?
doSomething()
callAPI() //Take time
doSomethingElse()
Why not use multi-threading then?
Because it's costly, hard to maintain and consume your hardware resources
Coroutines
- Same as threads they are able to execute instructions
- Coroutines are executed within a thread meaning you can run thousands of coroutines without crashing your app
- They are suspendable => start the execution of a coroutine, pause the execution and resume it later
- coroutine have their own context which you as coder have control of.
How to make a function callable in a coroutine context
fun doSomething(){
//...
}
suspend fun doSomething(){
//...
}
suspend functions can only be called from coroutines or other functions with suspension points. They cannot be called by normal code
How to start a coroutine ?
launch {
doSomething()
}
⚠️Spoiler Alert⚠️
DO NOT USE WHAT YOU WILL SEE IN PRODUCTION
DO NOT USE WHAT YOU WILL SEE IN PRODUCTION
DO NOT USE WHAT YOU WILL SEE IN PRODUCTION
Previously on Amc's the Walking dead
Core concepts
- Same as threads they are able to execute instructions
- Coroutines are executed within a thread meaning you can run thousands of coroutines without crashing your app
- They are suspendable => start the execution of a coroutine, pause the execution and resume it later
- coroutine have their own context which you as coder have control of.
How to coroutine
suspend fun doSomething(){
//...
}
launch {
doSomething()
}
fun doSomething(){
//...
}
doSomething()
Start a coroutine
fun main(args: Array<String>) {
launch { // launch new coroutine in background and continue
delay(1000L) // non-blocking delay for 1 second (default time unit is ms)
println("World!") // print after delay
}
println("Hello,") // main thread continues while coroutine is delayed
Thread.sleep(2000L) // block main thread for 2 seconds to keep JVM alive
}
Start a coroutine
fun main(args: Array<String>) = runBlocking<Unit> {
val time = measureTimeMillis {
val one = async { doSomethingUsefulOne() }
val two = async { doSomethingUsefulTwo() }
println("The answer is ${one.await() + two.await()}")
}
println("Completed in $time ms")
}
The main difference between async and launch is that launch is used for starting a computation that isn't expected to return a specific result. launch returns Job, which represents the coroutine. It is possible to wait until it completes by calling Job.join() but rather use async in that case.
Start a coroutine
suspend fun demo() : Any = TODO()
fun main(args: Array<String>) {
// demo() // this alone wouldn't compile... Error:() Kotlin: Suspend function 'demo' should be called only from a coroutine or another suspend function
// whereas the following works as intended:
runBlocking {
demo()
} // it also waits until demo()-call is finished which wouldn't happen if you use launch
}
runBlocking is used as a bridge between regular and suspend functions, between blocking and non-blocking worlds. It works as an adaptor for starting the top-level main coroutine and is intended primarily to be used in main functions and in tests.
PLEASE AVOID IT WHEN YOU ARE UNSURE
Coroutines run on the same thread, unless you tell otherwise
async{ ... }
async(Dispatchers.DEFAULT){ ... }
Use dispatcher from the outer scope
Use a shared pool on the JVM
Dispatchers
- Dispatchers.Default - for CPU intense work (e.g. sorting a big list)
- Dispatchers.Main - what this will be depends on what you've added to your programs runtime dependencies (e.g. kotlinx-coroutines-android, for the UI thread in Android)
- Dispatchers.Unconfined - runs coroutines unconfined on no specific thread
- Dispatchers.IO - for heavy IO work (e.g. long-running database queries)
Coroutine Context
Every coroutine in Kotlin has a context that is represented by an instance of CoroutineContext interface. A context is a set of elements and current coroutine context is available via coroutineContext property:
fun main() = runBlocking<Unit> {
println("My context is: $coroutineContext")
}
// My context is: [CoroutineId(1), "coroutine#1":BlockingCoroutine{Active}@5b80350b, BlockingEventLoop@5d6f64b1]
Coroutine Scope
There is also an interface called CoroutineScope that consists of a sole property — val coroutineContext: CoroutineContext. It has nothing else but a context
public interface CoroutineScope {
/**
* The context of this scope.
* Context is encapsulated by the scope and used for implementation of coroutine builders that are extensions on the scope.
* Accessing this property in general code is not recommended for any purposes except accessing the [Job] instance for advanced usages.
*
* By convention, should contain an instance of a [job][Job] to enforce structured concurrency.
*/
public val coroutineContext: CoroutineContext
}
Guess the output
package coroutines
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
fun main() {
println("🍔")
runBlocking() {
launch {
delay(1000)
println("🍕")
}
launch {
delay(500)
println("🍰")
}
}
println("🍦")
}
Guess the output
package coroutines
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.GlobalScope
fun main(){
println("🍔")
runBlocking() {
GlobalScope.launch {
delay(1000)
println("🍕")
}
GlobalScope.launch {
delay(500)
println("🍰")
}
}
println("🍦")
}
Co routines
By Issam Hammi
Co routines
training on coroutines with payment team
- 566