$30 off During Our Annual Pro Sale. View Details »

Introduction to Kotlin Coroutines

Introduction to Kotlin Coroutines

Brief introduction to Kotlin Coroutines, presented before a workshop of introduction to Coroutines

David González

February 27, 2019
Tweet

More Decks by David González

Other Decks in Programming

Transcript

  1. Introduction to
    Kotlin Coroutines
    KugBel & GDGBrussels February 2019

    View Slide

  2. Async is hard!

    View Slide

  3. Solution 1: Callbacks
    loadImageAsync().whenComplete { image ->
    runOnUiThread {
    setImage(image)
    }
    }

    View Slide

  4. Solution 2: async / await
    async(UI) {
    val image = loadImageAsync(url).await()
    setImage(image)
    }

    View Slide

  5. What is a Coroutine?

    View Slide

  6. Coroutines are like lightweight threads
    Coroutine is a sequence of instructions
    Multiple coroutines can be executed concurrently
    Share resources such as memory

    View Slide

  7. Computation that can be suspended
    Thread is not blocked!

    View Slide

  8. Key Concepts
    Coroutine Builders
    Suspending functions
    Coroutine Scope
    Coroutine Dispatchers

    View Slide

  9. Coroutine Builders
    launch - fire and forget
    async - returns a Deferred

    View Slide

  10. Our first coroutine
    fun main() {
    GlobalScope.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
    }
    Hello,
    World!

    View Slide

  11. Suspending function
    A function that can suspend the execution of a coroutine
    It can be started, paused and resumed at a later time
    Can only be called within a coroutine or from another suspending function

    View Slide

  12. Our first coroutine
    fun main() {
    GlobalScope.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
    }

    View Slide

  13. Our first suspending function
    fun main() {
    launch { doWorld() }
    println("Hello,")
    }
    // this is your first suspending function
    suspend fun doWorld() {
    delay(1000L)
    println("World!")
    }
    Hello,
    World!

    View Slide

  14. Composing suspending functions
    suspend fun doSomethingUsefulOne(): Int {
    delay(1000L) // pretend we are doing something useful here
    return 13
    }
    suspend fun doSomethingUsefulTwo(): Int {
    delay(1000L) // pretend we are doing something useful here, too
    return 29
    }

    View Slide

  15. Composing suspending functions
    fun main() = runBlocking {
    val time = measureTimeMillis {
    val one = doSomethingUsefulOne()
    val two = doSomethingUsefulTwo()
    println("The answer is ${one + two}")
    }
    println("Completed in $time ms")
    }
    The answer is 42
    Completed in 2017 ms

    View Slide

  16. Composing suspending functions
    fun main() = runBlocking {
    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 answer is 42
    Completed in 1017 ms

    View Slide

  17. Coroutine Scope
    Defines a scope for new coroutines
    A scope controls the lifetime of coroutines through its job
    Every coroutine builder is an extension on CoroutineScope and inherits its coroutineContext to
    automatically propagate both context elements and cancellation.

    View Slide

  18. Composing suspending functions
    fun main() = runBlocking {
    val time = measureTimeMillis {
    val one = async { doSomethingUsefulOne() }
    val two = async { doSomethingUsefulTwo() }
    println("The answer is ${one.await() + two.await()}")
    }
    println("Completed in $time ms")
    }

    View Slide

  19. Composing suspending functions
    suspend fun concurrentSum(): Int = coroutineScope {
    val one = async { doSomethingUsefulOne() }
    val two = async { doSomethingUsefulTwo() }
    one.await() + two.await()
    }
    fun main() = runBlocking {
    val time = measureTimeMillis {
    println("The answer is ${concurrentSum()}")
    }
    println("Completed in $time ms")
    }
    The answer is 42
    Completed in 1017 ms

    View Slide

  20. Coroutine Dispatchers
    Determines the thread a coroutine runs on
    It can confine a coroutine to a specific thread, a threadpool or let it run unconfined

    View Slide

  21. Coroutine Dispatchers
    fun main() = runBlocking {
    launch(Dispatchers.Main) { // context of the parent, main runBlocking coroutine
    println("main runBlocking : I'm working in thread ${Thread.currentThread().name}")
    }
    launch(Dispatchers.Unconfined) { // not confined -- will work with main thread
    println("Unconfined : I'm working in thread ${Thread.currentThread().name}")
    }
    launch(Dispatchers.Default) { // will get dispatched to DefaultDispatcher
    println("Default : I'm working in thread ${Thread.currentThread().name}")
    }
    launch(newSingleThreadContext("MyOwnThread")) { // will get its own new thread
    println("newSingleThreadContext: I'm working in thread ${Thread.currentThread().name}")
    }
    }

    View Slide

  22. Coroutine Dispatchers
    main runBlocking : I 'm working in thread main
    Unconfined : I' m working in thread main
    Default : I 'm working in thread DefaultDispatcher-worker-1
    newSingleThreadContext: I' m working in thread MyOwnThread

    View Slide

  23. How can I use them?

    View Slide

  24. View Slide

  25. Let’s get to work
    https://codelabs.developers.google.com/codelabs/kotlin-coroutines
    $ git clone https://github.com/googlecodelabs/kotlin-coroutines.git

    View Slide