Grokking Coroutines (MinneBar)

D225ebf0faa666ac7655cc7e4689283c?s=47 Daniel Lew
October 13, 2020

Grokking Coroutines (MinneBar)

What are coroutines, really?

Given at MinneBar 2020.

D225ebf0faa666ac7655cc7e4689283c?s=128

Daniel Lew

October 13, 2020
Tweet

Transcript

  1. Grokking Coroutines @danlew42

  2. “Essentially, coroutines are light-weight threads.” ~Kotlin Documentation

  3. myScope.launch { val image = downloadImage() displayImage(image) } suspend fun

    downloadImage() = withContext(Dispatchers.IO) { … } fun displayImage(image: Image)
  4. sequence { var cur = 1 var next = 1

    while (true) { yield(cur) val tmp = cur + next cur = next next = tmp } }
  5. What are coroutines?

  6. Subroutines fun sumSquaredValues(values: List<Int>): Int { return values.sumBy { value

    -> square(value) } } fun square(value: Int): Int = value * value
  7. Routine Subroutine

  8. Coroutine Coroutine

  9. val iterator = sequence.iterator() while (iterator.hasNext()) { val next =

    iterator.next() println(next) } sequence { var cur = 1 var next = 1 while (true) { yield(cur) val tmp = cur + next cur = next next = tmp } } Consumer Producer
  10. val iterator = sequence.iterator() while (iterator.hasNext()) { val next =

    iterator.next() println(next) } sequence { var cur = 1 var next = 1 while (true) { yield(cur) val tmp = cur + next cur = next next = tmp } } Consumer Producer
  11. None
  12. class Fibonacci { var cur = 1 var next =

    1 fun next(): Int { val toReturn = cur val tmp = cur + next cur = next next = tmp return toReturn } } sequence { var cur = 1 var next = 1 while (true) { yield(cur) val tmp = cur + next cur = next next = tmp } } Versus
  13. Multiple Suspend Points sequence { yield(1) // first Fibonacci number

    var cur = 1 var next = 1 while (true) { yield(next) // next Fibonacci number val tmp = cur + next cur = next next = tmp } }
  14. Why use coroutines?

  15. Why use coroutines? • Another tool for writing good code

    • Two ways to use tool: • Code Structure • Concurrency
  16. https://www.flickr.com/photos/117693452@N04/12547460924

  17. https://www.maxpixel.net/Lana-Frame-Threads-Thread-Handmade-Weaving-3019254

  18. Blocking Functions fun main() { print(calculateMeaningOfLife()) } fun calculateMeaningOfLife(): Int

    { // Calculates for 7.5 million years, then... return 42 }
  19. Non-Blocking Function suspend fun calculateMeaningOfLife(): Int { delay(7.5 million years)

    return 42 }
  20. Blocking vs. Nonblocking Blocking Blocked During I/O Non-Blocking Waiting During

    I/O Doing other work
  21. Two Tasks, One Thread suspend fun task(name: String, delay: Long)

    { joinAll( async { doSomething("First", 10) }, async { doSomething("Second", 5) } ) } suspend fun doSomething(name: String, delay: Long) { println("$name START (${Thread.currentThread().name})") delay(delay) println("$name END (${Thread.currentThread().name})") } First START (main) Second START (main) Second END (main) First END (main)
  22. Threads == preemptive multitasking Coroutines == cooperative multitasking

  23. Callback Hell requestRandomUrl { url -> downloadImage(url) { image ->

    displayImage(image) } } myScope.launch { val url = requestRandomUrl() val image = downloadImage(url) displayImage(image) } Vs
  24. Why use coroutines? • Concurrency • Coroutines *are* like light-weight

    threads! • …In any language! • Code Structure • Coroutines enable simpler code
  25. Kotlin Coroutines

  26. kotlin.coroutines (stdlib) kotlinx.coroutines (library)

  27. kotlin.coroutines (stdlib) kotlinx.coroutines (library)

  28. Stdlib Basics • Suspending functions • A way to start

    suspending functions • Contexts
  29. Suspend Keyword

  30. Start Suspending Functions suspend fun mySuspendingFunction() fun <T> (suspend ()

    -> T).startCoroutine(completion: Continuation<T>) fun main() { ::mySuspendingFunction.startCoroutine( Continuation(EmptyCoroutineContext) { } ) }
  31. Coroutine Context • Store useful info about coroutine • Dispatcher

    • Job • Debug info
  32. Coroutine Library

  33. myScope.launch { val image = downloadImage() displayImage(image) } suspend fun

    downloadImage() = withContext(Dispatchers.IO) { … } fun displayImage(image: Image)
  34. myScope.launch { val image = downloadImage() displayImage(image) } suspend fun

    downloadImage() = withContext(Dispatchers.IO) { … } fun displayImage(image: Image)
  35. myScope.launch { val image = downloadImage() displayImage(image) } suspend fun

    downloadImage() = withContext(Dispatchers.IO) { … } fun displayImage(image: Image)
  36. myScope.launch { val image = downloadImage() displayImage(image) } suspend fun

    downloadImage() = withContext(Dispatchers.IO) { … } fun displayImage(image: Image)
  37. Review • Coroutines are suspending functions • Suspending functions are

    useful for concurrency • Kotlin stdlib provides coroutine support • Kotlin coroutine library adds practical functions for coroutines
  38. More Info • Longer Talk: https://youtu.be/Axq8LdQqQGQ • Links: github.com/Kotlin/kotlinx.coroutines/#documentation •

    Roman Elizarov: medium.com/@elizarov • Android + Coroutines: medium.com/@objcode • Structured concurrency: vorpus.org/blog/notes-on-structured- concurrency-or-go-statement-considered-harmful/
  39. @danlew42