Skip to content

m0rk4/intro-coroutines

 
 

Repository files navigation

official JetBrains project GitHub license

Introduction to Coroutines and Channels Hands-On Lab

This repository is the code corresponding to the Introduction to Coroutines and Channels Hands-On Lab.

Concurrency sample

fun main() = runBlocking {
    val deferred: Deferred<Int> = async(Dispatchers.Default) {
        loadData()
    }
    log("waiting...")
    log(deferred.await())
}

suspend fun loadData(): Int {
    log("loading...")
    delay(1000L)
    log("loaded!")
    return 42
}
  1. main coroutine is created on Main thread (runBlocking)
  2. loadData coroutine is created on Different thread (async(Dispatchers.Default))
  3. log 'waiting' (main) and log 'loading' (loadData) are executed simultaneously (no guarantee which one is first)
  4. main (await()) and loadData (delay) suspend simultaneously and release their threads free (no guarantee which one is first)
  5. loadData resumes after 1s, logs 'loaded' and finishes with value 42 (coroutine is finished)
  6. finish of loadData coroutine resumes main coroutine, main coroutine prints 42 and finishes as well

img.png

When async creates coroutine on the same thread:

val deferred: Deferred<Int> = async { loadData() }
  1. main coroutine is created on Main thread (runBlocking)
  2. loadData coroutine is created on SAME Main thread (async)
  3. log 'waiting' from main coroutine (we can't switch to loadData yet, we are busy with main)
  4. main (await) is suspended and main thread is free
  5. loadData coroutine starts execution, prints 'loading', suspends for 1s, finishes with 42
  6. releases main thread and resumes main coroutine, main coroutine prints 42 and finishes as well

img_1.png

Inheriting the context by default

With structured concurrency, you can specify the major context elements (like dispatcher) once, when creating the top-level coroutine. All the nested coroutines then inherit the context and modify it only if needed.

Channels

Channel is like a blocking queue, but 'suspendable' queue, when send() and receive() are suspended depends on channel type.

// 0 size: send() is suspended until receive() called and vice versa
val rendezvousChannel = Channel<String>()

// fixed size: send() is suspended if channel is full, receive is suspended if channel is empty
val bufferedChannel = Channel<String>(10)

// send() is not suspended - new element overrides next, receive() receives only last element (suspended if channel is empty) 
val conflatedChannel = Channel<String>(CONFLATED)

// unlimited size: send() is not suspended (danger for OOM), receive is suspended if channel is empty
val unlimitedChannel = Channel<String>(UNLIMITED)

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Kotlin 100.0%