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

Grokking Coroutines (MinneBar)

Grokking Coroutines (MinneBar)

What are coroutines, really?

Given at MinneBar 2020.

Daniel Lew
PRO

October 13, 2020
Tweet

More Decks by Daniel Lew

Other Decks in Programming

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