Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Android Makers -- Concurrency doesn’t have to b...

Android Makers -- Concurrency doesn’t have to be hard: 
Kotlin Coroutines & Channels

Presentation of the fundamentals of Kotlin Coroutines, Channels and Flows presented at Android Makers'19
*NOTE* Several animations are not present in this slide deck; the presentation switched between live coding and slides

Jag Saund

April 24, 2019
Tweet

Other Decks in Programming

Transcript

  1. fun main() { val orders = listOf( Menu.Cappuccino(CoffeeBean.Regular, Milk.Whole), Menu.Cappuccino(CoffeeBean.Premium,

    Milk.Breve), Menu.Cappuccino(CoffeeBean.Regular, Milk.NonFat), Menu.Cappuccino(CoffeeBean.Decaf, Milk.Whole), Menu.Cappuccino(CoffeeBean.Regular, Milk.NonFat), Menu.Cappuccino(CoffeeBean.Decaf, Milk.NonFat) ) } https://jagstalk.page.link/examples
  2. fun main() { val orders = listOf(...) orders.forEach { }

    } https://jagstalk.page.link/examples
  3. fun main() { val orders = listOf(...) orders.forEach { val

    groundBeans = grindCoffeeBeans(it.beans) } } https://jagstalk.page.link/examples
  4. fun main() { val orders = listOf(...) orders.forEach { val

    groundBeans = grindCoffeeBeans(it.beans) val espresso = pullEspressoShot(groundBeans) } } https://jagstalk.page.link/examples
  5. fun main() { val orders = listOf(...) orders.forEach { val

    groundBeans = grindCoffeeBeans(it.beans) val espresso = pullEspressoShot(groundBeans) val steamedMilk = steamMilk(it.milk) } } https://jagstalk.page.link/examples
  6. fun main() { val orders = listOf(...) orders.forEach { val

    groundBeans = grindCoffeeBeans(it.beans) val espresso = pullEspressoShot(groundBeans) val steamedMilk = steamMilk(it.milk) val cappuccino = makeCappuccino(it, espresso, steamedMilk) } } https://jagstalk.page.link/examples
  7. fun main() { val orders = listOf(...) orders.forEach { val

    groundBeans = grindCoffeeBeans(it.beans) val espresso = pullEspressoShot(groundBeans) val steamedMilk = steamMilk(it.milk) val cappuccino = makeCappuccino(it, espresso, steamedMilk) log("serve: $cappuccino") } } https://jagstalk.page.link/examples
  8. fun main() { val orders = listOf(...) val time =

    measureTimeMillis { orders.forEach { val groundBeans = grindCoffeeBeans(it.beans) val espresso = pullEspressoShot(groundBeans) val steamedMilk = steamMilk(it.milk) val cappuccino = makeCappuccino(it, espresso, steamedMilk) log("serve: $cappuccino") } } log("time: $time ms") } https://jagstalk.page.link/examples
  9. fun main() { val orders = listOf(...) val time =

    measureTimeMillis { orders.forEach { val groundBeans = grindCoffeeBeans(it.beans) val espresso = pullEspressoShot(groundBeans) val steamedMilk = steamMilk(it.milk) val cappuccino = makeCappuccino(it, espresso, steamedMilk) log("serve: $cappuccino") } } log("time: $time ms") } https://jagstalk.page.link/examples
  10. fun main() {...} private fun grindCoffeeBeans(beans: CoffeeBean): CoffeeBean.GroundBeans { log("grinding

    coffee beans") sleep(1000) return CoffeeBean.GroundBeans(beans) } private fun pullEspressoShot(groundBeans: CoffeeBean.GroundBeans): Espresso { log("pulling espresso shot") sleep(600) return Espresso(groundBeans) } private fun steamMilk(milk: Milk): Milk.SteamedMilk { log("steaming milk") sleep(300) return Milk.SteamedMilk(milk) } private fun makeCappuccino(order: Menu.Cappuccino, espresso: Espresso, steamedMilk: Milk.SteamedMilk): Beverage.Cappuccino { log("making cappuccino") sleep(100) return Beverage.Cappuccino(order, espresso, steamedMilk) } https://jagstalk.page.link/examples
  11. fun main() { val orders = listOf(...) val time =

    measureTimeMillis { orders.forEach { val groundBeans = grindCoffeeBeans(it.beans) val espresso = pullEspressoShot(groundBeans) val steamedMilk = steamMilk(it.milk) val cappuccino = makeCappuccino(it, espresso, steamedMilk) log("serve: $cappuccino") } } log("time: $time ms") } private fun grindCoffeeBeans(beans: CoffeeBean): CoffeeBean.GroundBeans { ... } private fun pullEspressoShot(groundBeans: CoffeeBean.GroundBeans): Espresso { ... } private fun steamMilk(milk: Milk): Milk.SteamedMilk { ... } private fun makeCappuccino(order: Menu.Cappuccino, espresso: Espresso, steamedMilk: Milk.SteamedMilk): Beverage.Cappuccino { ... } https://jagstalk.page.link/examples
  12. fun main() { val orders = listOf(...) val time =

    measureTimeMillis { } log("time: $time ms") } private fun processOrders(orders: List<Menu.Cappuccino>) { } orders.forEach { val groundBeans = grindCoffeeBeans(it.beans) val espresso = pullEspressoShot(groundBeans) val steamedMilk = steamMilk(it.milk) val cappuccino = makeCappuccino(it, espresso, steamedMilk) log("serve: $cappuccino") } https://jagstalk.page.link/examples
  13. private fun processOrders(orders: List<Menu.Cappuccino>) { } fun main() { val

    orders = listOf(...) val time = measureTimeMillis { processOrders(orders) } log("time: $time ms") } https://jagstalk.page.link/examples orders.forEach { val groundBeans = grindCoffeeBeans(it.beans) val espresso = pullEspressoShot(groundBeans) val steamedMilk = steamMilk(it.milk) val cappuccino = makeCappuccino(it, espresso, steamedMilk) log("serve: $cappuccino") }
  14. fun main() { val orders = listOf(...) val time =

    measureTimeMillis { launch { processOrders(orders) } launch { processOrders(orders) } } log("time: $time ms”) } private fun processOrders(orders: List<Menu.Cappuccino>) { orders.forEach { val groundBeans = grindCoffeeBeans(it.beans()) val espresso = pullEspressoShot(groundBeans) val steamedMilk = steamMilk(it.milk()) val cappuccino = makeCappuccino(it, espresso, steamedMilk) log("serve: $cappuccino") } } https://jagstalk.page.link/examples
  15. fun main() = runBlocking { val orders = listOf(...) val

    time = measureTimeMillis { launch { processOrders(orders) } launch { processOrders(orders) } } log("time: $time ms”) } private fun processOrders(orders: List<Menu.Cappuccino>) { orders.forEach { val groundBeans = grindCoffeeBeans(it.beans()) val espresso = pullEspressoShot(groundBeans) val steamedMilk = steamMilk(it.milk()) val cappuccino = makeCappuccino(it, espresso, steamedMilk) log("serve: $cappuccino") } } https://jagstalk.page.link/examples
  16. fun main() = runBlocking { val orders = listOf(...) val

    time = measureTimeMillis { launch(CoroutineName("barista-1")) { processOrders(orders) } launch(CoroutineName("barista-2")) { processOrders(orders) } } log("time: $time ms”) } private fun processOrders(orders: List<Menu.Cappuccino>) { orders.forEach { val groundBeans = grindCoffeeBeans(it.beans()) val espresso = pullEspressoShot(groundBeans) val steamedMilk = steamMilk(it.milk()) val cappuccino = makeCappuccino(it, espresso, steamedMilk) log("serve: $cappuccino") } } https://jagstalk.page.link/examples
  17. fun main() = runBlocking { val orders = listOf(...) val

    time = measureTimeMillis { launch(CoroutineName("barista-1")) { processOrders(orders) } launch(CoroutineName("barista-2")) { processOrders(orders) } } log("time: $time ms”) } private fun processOrders(orders: List<Menu.Cappuccino>) { orders.forEach { val groundBeans = grindCoffeeBeans(it.beans()) val espresso = pullEspressoShot(groundBeans) val steamedMilk = steamMilk(it.milk()) val cappuccino = makeCappuccino(it, espresso, steamedMilk) log("serve: $cappuccino") } } https://jagstalk.page.link/examples
  18. private fun grindCoffeeBeans(beans: CoffeeBean): CoffeeBean.GroundBeans { log("grinding coffee beans") sleep(1000)

    return CoffeeBean.GroundBeans(beans) } private fun pullEspressoShot(groundBeans: CoffeeBean.GroundBeans): Espresso { log("pulling espresso shot") sleep(600) return Espresso(groundBeans) } private fun steamMilk(milk: Milk): Milk.SteamedMilk { log("steaming milk") sleep(300) return Milk.SteamedMilk(milk) } private fun makeCappuccino(order: Menu.Cappuccino, espresso: Espresso, steamedMilk: Milk.SteamedMilk): Beverage.Cappuccino { log("making cappuccino") sleep(100) return Beverage.Cappuccino(order, espresso, steamedMilk) } fun main() {...} https://jagstalk.page.link/examples
  19. private suspend fun grindCoffeeBeans(beans: CoffeeBean): CoffeeBean.GroundBeans { log("grinding coffee beans")

    delay(1000) return CoffeeBean.GroundBeans(beans) } private suspend fun pullEspressoShot(groundBeans: CoffeeBean.GroundBeans): Espresso { log("pulling espresso shot") delay(600) return Espresso(groundBeans) } private suspend fun steamMilk(milk: Milk): Milk.SteamedMilk { log("steaming milk") delay(300) return Milk.SteamedMilk(milk) } private suspend fun makeCappuccino(order: Menu.Cappuccino, espresso: Espresso, steamedMilk: Milk.SteamedMilk): Beverage.Cappuccino { log("making cappuccino") delay(100) return Beverage.Cappuccino(order, espresso, steamedMilk) } fun main() {...} https://jagstalk.page.link/examples
  20. fun main() {...} private suspend fun grindCoffeeBeans(beans: CoffeeBean): CoffeeBean.GroundBeans {

    log("grinding coffee beans") delay(1000) return CoffeeBean.GroundBeans(beans) } private suspend fun pullEspressoShot(groundBeans: CoffeeBean.GroundBeans): Espresso { log("pulling espresso shot") delay(600) return Espresso(groundBeans) } private suspend fun steamMilk(milk: Milk): Milk.SteamedMilk { log("steaming milk") delay(300) return Milk.SteamedMilk(milk) } private suspend fun makeCappuccino(order: Menu.Cappuccino, espresso: Espresso, steamedMilk: Milk.SteamedMilk): Beverage.Cappuccino { log("making cappuccino") delay(100) return Beverage.Cappuccino(order, espresso, steamedMilk) } https://jagstalk.page.link/examples
  21. private suspend fun grindCoffeeBeans(beans: CoffeeBean): CoffeeBean.GroundBeans { ... } private

    suspend fun pullEspressoShot(groundBeans: CoffeeBean.GroundBeans): Espresso { ... } private suspend fun steamMilk(milk: Milk): Milk.SteamedMilk { ... } private suspend fun makeCappuccino(order: Menu.Cappuccino, espresso: Espresso, steamedMilk: Milk.SteamedMilk): Beverage.Cappuccino { ... } fun main() {...} https://jagstalk.page.link/examples
  22. private fun processOrders(orders: List<Menu.Cappuccino>) { orders.forEach { val groundBeans =

    grindCoffeeBeans(it.beans()) val espresso = pullEspressoShot(groundBeans) val steamedMilk = steamMilk(it.milk()) val cappuccino = makeCappuccino(it, espresso, steamedMilk) log("serve: $cappuccino") } } private suspend fun grindCoffeeBeans(beans: CoffeeBean): CoffeeBean.GroundBeans { ... } private suspend fun pullEspressoShot(groundBeans: CoffeeBean.GroundBeans): Espresso { ... } private suspend fun steamMilk(milk: Milk): Milk.SteamedMilk { ... } private suspend fun makeCappuccino(order: Menu.Cappuccino, espresso: Espresso, steamedMilk: Milk.SteamedMilk): Beverage.Cappuccino { ... } fun main() {...} https://jagstalk.page.link/examples
  23. private suspend fun processOrders(orders: List<Menu.Cappuccino>) { orders.forEach { val groundBeans

    = grindCoffeeBeans(it.beans()) val espresso = pullEspressoShot(groundBeans) val steamedMilk = steamMilk(it.milk()) val cappuccino = makeCappuccino(it, espresso, steamedMilk) log("serve: $cappuccino") } } private suspend fun grindCoffeeBeans(beans: CoffeeBean): CoffeeBean.GroundBeans { ... } private suspend fun pullEspressoShot(groundBeans: CoffeeBean.GroundBeans): Espresso { ... } private suspend fun steamMilk(milk: Milk): Milk.SteamedMilk { ... } private suspend fun makeCappuccino(order: Menu.Cappuccino, espresso: Espresso, steamedMilk: Milk.SteamedMilk): Beverage.Cappuccino { ... } fun main() {...} https://jagstalk.page.link/examples
  24. fun main() = runBlocking { val orders = listOf(...) val

    time = measureTimeMillis { launch(CoroutineName("barista-1")) { processOrders(orders) } launch(CoroutineName("barista-2")) { processOrders(orders) } } log("time: $time ms”) } private suspend fun processOrders(orders: List<Menu.Cappuccino>) { orders.forEach { val groundBeans = grindCoffeeBeans(it.beans()) val espresso = pullEspressoShot(groundBeans) val steamedMilk = steamMilk(it.milk()) val cappuccino = makeCappuccino(it, espresso, steamedMilk) log("serve: $cappuccino") } } private suspend fun grindCoffeeBeans(beans: CoffeeBean): CoffeeBean.GroundBeans { ... } private suspend fun pullEspressoShot(groundBeans: CoffeeBean.GroundBeans): Espresso { ... } private suspend fun steamMilk(milk: Milk): Milk.SteamedMilk { ... } private suspend fun makeCappuccino(order: Menu.Cappuccino, espresso: Espresso, steamedMilk: Milk.SteamedMilk): Beverage.Cappuccino { ... } https://jagstalk.page.link/examples
  25. fun main() = runBlocking { val orders = listOf(...) val

    time = measureTimeMillis { coroutineScope { launch(CoroutineName("barista-1")) { processOrders(orders) } launch(CoroutineName("barista-2")) { processOrders(orders) } } } log("time: $time ms”) } private suspend fun processOrders(orders: List<Menu.Cappuccino>) { orders.forEach { val groundBeans = grindCoffeeBeans(it.beans()) val espresso = pullEspressoShot(groundBeans) val steamedMilk = steamMilk(it.milk()) val cappuccino = makeCappuccino(it, espresso, steamedMilk) log("serve: $cappuccino") } } private suspend fun grindCoffeeBeans(beans: CoffeeBean): CoffeeBean.GroundBeans { ... } private suspend fun pullEspressoShot(groundBeans: CoffeeBean.GroundBeans): Espresso { ... } private suspend fun steamMilk(milk: Milk): Milk.SteamedMilk { ... } private suspend fun makeCappuccino(order: Menu.Cappuccino, espresso: Espresso, steamedMilk: Milk.SteamedMilk): Beverage.Cappuccino { ... } https://jagstalk.page.link/examples
  26. fun main() = runBlocking { val orders = listOf(...) val

    time = measureTimeMillis { coroutineScope { launch(CoroutineName("barista-1")) { processOrders(orders) } launch(CoroutineName("barista-2")) { processOrders(orders) } } } log("time: $time ms”) } val ordersChannel = Channel<Menu>() orders.forEach { ordersChannel.send(it) } https://jagstalk.page.link/examples
  27. fun main() = runBlocking { val orders = listOf(...) val

    time = measureTimeMillis { coroutineScope { launch(CoroutineName("barista-1")) { processOrders(orders) } launch(CoroutineName("barista-2")) { processOrders(orders) } } } log("time: $time ms”) } val ordersChannel = Channel<Menu>() orders.forEach { ordersChannel.send(it) } https://jagstalk.page.link/examples
  28. fun main() = runBlocking { val orders = listOf(...) val

    time = measureTimeMillis { coroutineScope { launch(CoroutineName("barista-1")) { processOrders(ordersChannel) } launch(CoroutineName("barista-2")) { processOrders(ordersChannel) } } } log("time: $time ms”) } private suspend fun processOrders(ordersChannel: Channel<Menu.Cappuccino>) { ordersChannel.consumeEach { val groundBeans = grindCoffeeBeans(it.beans()) val espresso = pullEspressoShot(groundBeans) val steamedMilk = steamMilk(it.milk()) val cappuccino = makeCappuccino(it, espresso, steamedMilk) log("serve: $cappuccino") } } val ordersChannel = Channel<Menu>() orders.forEach { ordersChannel.send(it) } https://jagstalk.page.link/examples
  29. private suspend fun processOrders(ordersChannel: Channel<Menu.Cappuccino>) { ordersChannel.consumeEach { val groundBeans

    = grindCoffeeBeans(it.beans()) val espresso = pullEspressoShot(groundBeans) val steamedMilk = steamMilk(it.milk()) val cappuccino = makeCappuccino(it, espresso, steamedMilk) log("serve: $cappuccino") } } fun main() = runBlocking { val orders = listOf(...) val time = measureTimeMillis { coroutineScope { launch(CoroutineName("barista-1")) { processOrders(ordersChannel) } launch(CoroutineName("barista-2")) { processOrders(ordersChannel) } } } log("time: $time ms”) } val ordersChannel = Channel<Menu>() orders.forEach { ordersChannel.send(it) } https://jagstalk.page.link/examples
  30. val ordersChannel = Channel<Menu>() orders.forEach { ordersChannel.send(it) } fun main()

    = runBlocking { val orders = listOf(...) val time = measureTimeMillis { coroutineScope { launch(CoroutineName("barista-1")) { processOrders(ordersChannel) } launch(CoroutineName("barista-2")) { processOrders(ordersChannel) } } } log("time: $time ms”) } private suspend fun processOrders(ordersChannel: Channel<Menu.Cappuccino>) { ordersChannel.consumeEach { val groundBeans = grindCoffeeBeans(it.beans()) val espresso = pullEspressoShot(groundBeans) val steamedMilk = steamMilk(it.milk()) val cappuccino = makeCappuccino(it, espresso, steamedMilk) log("serve: $cappuccino") } } https://jagstalk.page.link/examples
  31. main coroutine val ordersChannel = Channel<Menu>() orders.forEach { ordersChannel.send(it) }

    fun main() = runBlocking { val orders = listOf(...) val time = measureTimeMillis { coroutineScope { launch(CoroutineName("barista-1")) { processOrders(ordersChannel) } launch(CoroutineName("barista-2")) { processOrders(ordersChannel) } } } log("time: $time ms”) } private suspend fun processOrders(ordersChannel: Channel<Menu.Cappuccino>) { ordersChannel.consumeEach { val groundBeans = grindCoffeeBeans(it.beans()) val espresso = pullEspressoShot(groundBeans) val steamedMilk = steamMilk(it.milk()) val cappuccino = makeCappuccino(it, espresso, steamedMilk) log("serve: $cappuccino") } } https://jagstalk.page.link/examples
  32. main coroutine channel main coroutine val ordersChannel = Channel<Menu>() orders.forEach

    { ordersChannel.send(it) } fun main() = runBlocking { val orders = listOf(...) val time = measureTimeMillis { coroutineScope { launch(CoroutineName("barista-1")) { processOrders(ordersChannel) } launch(CoroutineName("barista-2")) { processOrders(ordersChannel) } } } log("time: $time ms”) } private suspend fun processOrders(ordersChannel: Channel<Menu.Cappuccino>) { ordersChannel.consumeEach { val groundBeans = grindCoffeeBeans(it.beans()) val espresso = pullEspressoShot(groundBeans) val steamedMilk = steamMilk(it.milk()) val cappuccino = makeCappuccino(it, espresso, steamedMilk) log("serve: $cappuccino") } } https://jagstalk.page.link/examples
  33. main coroutine channel val ordersChannel = Channel<Menu>() orders.forEach { ordersChannel.send(it)

    } fun main() = runBlocking { val orders = listOf(...) val time = measureTimeMillis { coroutineScope { launch(CoroutineName("barista-1")) { processOrders(ordersChannel) } launch(CoroutineName("barista-2")) { processOrders(ordersChannel) } } } log("time: $time ms”) } private suspend fun processOrders(ordersChannel: Channel<Menu.Cappuccino>) { ordersChannel.consumeEach { val groundBeans = grindCoffeeBeans(it.beans()) val espresso = pullEspressoShot(groundBeans) val steamedMilk = steamMilk(it.milk()) val cappuccino = makeCappuccino(it, espresso, steamedMilk) log("serve: $cappuccino") } } https://jagstalk.page.link/examples
  34. main coroutine channel val ordersChannel = Channel<Menu>() orders.forEach { ordersChannel.send(it)

    } fun main() = runBlocking { val orders = listOf(...) val time = measureTimeMillis { coroutineScope { launch(CoroutineName("barista-1")) { processOrders(ordersChannel) } launch(CoroutineName("barista-2")) { processOrders(ordersChannel) } } } log("time: $time ms”) } private suspend fun processOrders(ordersChannel: Channel<Menu.Cappuccino>) { ordersChannel.consumeEach { val groundBeans = grindCoffeeBeans(it.beans()) val espresso = pullEspressoShot(groundBeans) val steamedMilk = steamMilk(it.milk()) val cappuccino = makeCappuccino(it, espresso, steamedMilk) log("serve: $cappuccino") } } https://jagstalk.page.link/examples
  35. main coroutine (suspended) channel val ordersChannel = Channel<Menu>() orders.forEach {

    ordersChannel.send(it) } fun main() = runBlocking { val orders = listOf(...) val time = measureTimeMillis { coroutineScope { launch(CoroutineName("barista-1")) { processOrders(ordersChannel) } launch(CoroutineName("barista-2")) { processOrders(ordersChannel) } } } log("time: $time ms”) } private suspend fun processOrders(ordersChannel: Channel<Menu.Cappuccino>) { ordersChannel.consumeEach { val groundBeans = grindCoffeeBeans(it.beans()) val espresso = pullEspressoShot(groundBeans) val steamedMilk = steamMilk(it.milk()) val cappuccino = makeCappuccino(it, espresso, steamedMilk) log("serve: $cappuccino") } } https://jagstalk.page.link/examples
  36. val ordersChannel = Channel<Menu>() orders.forEach { ordersChannel.send(it) } fun main()

    = runBlocking { val orders = listOf(...) val time = measureTimeMillis { coroutineScope { launch(CoroutineName("barista-1")) { processOrders(ordersChannel) } launch(CoroutineName("barista-2")) { processOrders(ordersChannel) } } } log("time: $time ms”) } private suspend fun processOrders(ordersChannel: Channel<Menu.Cappuccino>) { ordersChannel.consumeEach { val groundBeans = grindCoffeeBeans(it.beans()) val espresso = pullEspressoShot(groundBeans) val steamedMilk = steamMilk(it.milk()) val cappuccino = makeCappuccino(it, espresso, steamedMilk) log("serve: $cappuccino") } } https://jagstalk.page.link/examples
  37. fun main() = runBlocking { val orders = listOf(...) val

    time = measureTimeMillis { coroutineScope { launch(CoroutineName("barista-1")) { processOrders(ordersChannel) } launch(CoroutineName("barista-2")) { processOrders(ordersChannel) } } } log("time: $time ms") } val ordersChannel = Channel<Menu.Cappuccino>() launch(CoroutineName("cashier")) { orders.forEach { ordersChannel.send(it) } } private suspend fun processOrders(ordersChannel: Channel<Menu.Cappuccino>) { ordersChannel.consumeEach { val groundBeans = grindCoffeeBeans(it.beans()) val espresso = pullEspressoShot(groundBeans) val steamedMilk = steamMilk(it.milk()) val cappuccino = makeCappuccino(it, espresso, steamedMilk) log("serve: $cappuccino") } } https://jagstalk.page.link/examples
  38. fun main() = runBlocking { val orders = listOf(...) val

    time = measureTimeMillis { coroutineScope { launch(CoroutineName("barista-1")) { processOrders(ordersChannel) } launch(CoroutineName("barista-2")) { processOrders(ordersChannel) } } } log("time: $time ms") } val ordersChannel = produce(CoroutineName("cashier")) { orders.forEach { send(it) } } private suspend fun processOrders(ordersChannel: Channel<Menu.Cappuccino>) { ordersChannel.consumeEach { val groundBeans = grindCoffeeBeans(it.beans()) val espresso = pullEspressoShot(groundBeans) val steamedMilk = steamMilk(it.milk()) val cappuccino = makeCappuccino(it, espresso, steamedMilk) log("serve: $cappuccino") } } https://jagstalk.page.link/examples
  39. fun main() = runBlocking { val orders = listOf(...) val

    time = measureTimeMillis { coroutineScope { launch(CoroutineName("barista-1")) { processOrders(ordersChannel) } launch(CoroutineName("barista-2")) { processOrders(ordersChannel) } } } log("time: $time ms") } val ordersChannel = produce(CoroutineName("cashier")) { orders.forEach { send(it) } } private suspend fun processOrders(ordersChannel: Channel<Menu.Cappuccino>) { ordersChannel.consumeEach { val groundBeans = grindCoffeeBeans(it.beans()) val espresso = pullEspressoShot(groundBeans) val steamedMilk = steamMilk(it.milk()) val cappuccino = makeCappuccino(it, espresso, steamedMilk) log("serve: $cappuccino") } } https://jagstalk.page.link/examples produce coroutine
  40. class EspressoMachine { suspend fun pullEspressoShot(groundBeans: CoffeeBean.GroundBeans): Espresso { TODO("pull

    espresso shot not implemented") } suspend fun steamMilk(milk: Milk): Milk.SteamedMilk { TODO("steam milk not implemented") } } https://jagstalk.page.link/examples
  41. class EspressoMachine { suspend fun pullEspressoShot(groundBeans: CoffeeBean.GroundBeans): Espresso { TODO("pull

    espresso shot not implemented") } suspend fun steamMilk(milk: Milk): Milk.SteamedMilk { TODO("steam milk not implemented") } private suspend fun processEspressoShot(groundBeans: CoffeeBean.GroundBeans): Espresso { log("pulling espresso shot") delay(600) return Espresso(groundBeans) } private suspend fun processSteamMilk(milk: Milk): Milk.SteamedMilk { log("steaming milk") delay(300) return Milk.SteamedMilk(milk) } } https://jagstalk.page.link/examples
  42. class EspressoMachine { suspend fun pullEspressoShot(groundBeans: CoffeeBean.GroundBeans): Espresso { TODO("pull

    espresso shot not implemented") } suspend fun steamMilk(milk: Milk): Milk.SteamedMilk { TODO("steam milk not implemented") } } private suspend fun processEspressoShot(groundBeans: CoffeeBean.GroundBeans): Espresso {...} private suspend fun processSteamMilk(milk: Milk): Milk.SteamedMilk {…} https://jagstalk.page.link/examples
  43. class EspressoMachine { private val portafilterOne: SendChannel<CoffeeBean.GroundBeans> = actor {

    consumeEach { groundBeans -> val espresso = processEspressoShot(groundBeans) TODO("deliver espresso shot to sender") } } suspend fun pullEspressoShot(groundBeans: CoffeeBean.GroundBeans): Espresso { TODO("pull espresso shot not implemented") } suspend fun steamMilk(milk: Milk): Milk.SteamedMilk { TODO("steam milk not implemented") } } private suspend fun processEspressoShot(groundBeans: CoffeeBean.GroundBeans): Espresso {...} private suspend fun processSteamMilk(milk: Milk): Milk.SteamedMilk {…} https://jagstalk.page.link/examples
  44. class EspressoMachine { private val portafilterOne: SendChannel<CoffeeBean.GroundBeans> = actor {

    consumeEach { groundBeans -> val espresso = processEspressoShot(groundBeans) TODO("deliver espresso shot to sender") } }
 private val portafilterTwo: SendChannel<CoffeeBean.GroundBeans> = actor { consumeEach { groundBeans -> val espresso = processEspressoShot(groundBeans) TODO("deliver espresso shot to sender") } } suspend fun pullEspressoShot(groundBeans: CoffeeBean.GroundBeans): Espresso { TODO("pull espresso shot not implemented") } suspend fun steamMilk(milk: Milk): Milk.SteamedMilk { TODO("steam milk not implemented") } private suspend fun processEspressoShot(groundBeans: CoffeeBean.GroundBeans): Espresso {...} private suspend fun processSteamMilk(milk: Milk): Milk.SteamedMilk {...} } https://jagstalk.page.link/examples
  45. Barista Portafilter 1 Portafilter 2 select Select Like a switch

    statement Works on Send and Receive Shape Data Flow https://jagstalk.page.link/examples
  46. class EspressoMachine { private val portafilterOne: SendChannel<CoffeeBean.GroundBeans> = actor {

    consumeEach { groundBeans -> val espresso = processEspressoShot(groundBeans) TODO("deliver espresso shot to sender") } }
 private val portafilterTwo: SendChannel<CoffeeBean.GroundBeans> = actor { consumeEach { groundBeans -> val espresso = processEspressoShot(groundBeans) TODO("deliver espresso shot to sender") } } suspend fun pullEspressoShot(groundBeans: CoffeeBean.GroundBeans): Espresso { TODO("pull espresso shot not implemented") } suspend fun steamMilk(milk: Milk): Milk.SteamedMilk { TODO("steam milk not implemented") } private suspend fun processEspressoShot(groundBeans: CoffeeBean.GroundBeans): Espresso {...} private suspend fun processSteamMilk(milk: Milk): Milk.SteamedMilk {...} } https://jagstalk.page.link/examples
  47. class EspressoMachine { private val portafilterOne: SendChannel<CoffeeBean.GroundBeans> = actor {...}


    private val portafilterTwo: SendChannel<CoffeeBean.GroundBeans> = actor {...} suspend fun pullEspressoShot(groundBeans: CoffeeBean.GroundBeans): Espresso { return select { portafilterOne.onSend(groundBeans) { TODO("sent to portafilter one - wait for result") } portafilterTwo.onSend(groundBeans) { TODO("sent to portafilter two - wait for result") } } } ... } https://jagstalk.page.link/examples
  48. class EspressoMachine { private val portafilterOne: SendChannel<CoffeeBean.GroundBeans> = actor {...}


    private val portafilterTwo: SendChannel<CoffeeBean.GroundBeans> = actor {...} suspend fun pullEspressoShot(groundBeans: CoffeeBean.GroundBeans): Espresso { return select { portafilterOne.onSend(groundBeans) { TODO("sent to portafilter one - wait for result") } portafilterTwo.onSend(groundBeans) { TODO("sent to portafilter two - wait for result") } } } ... } https://jagstalk.page.link/examples
  49. class EspressoMachine { private data class EspressoShotRequest( val deferredEspressoShot: CompletableDeferred<Espresso>,

    val groundBeans: CoffeeBean.GroundBeans ) private val portafilterOne: SendChannel<CoffeeBean.GroundBeans> = actor {...}
 private val portafilterTwo: SendChannel<CoffeeBean.GroundBeans> = actor {...} suspend fun pullEspressoShot(groundBeans: CoffeeBean.GroundBeans): Espresso { return select { portafilterOne.onSend(groundBeans) { TODO("sent to portafilter one - wait for result") } portafilterTwo.onSend(groundBeans) { TODO("sent to portafilter two - wait for result") } } } ... } https://jagstalk.page.link/examples
  50. class EspressoMachine { private data class EspressoShotRequest( val deferredEspressoShot: CompletableDeferred<Espresso>,

    val groundBeans: CoffeeBean.GroundBeans ) private val portafilterOne: SendChannel<EspressoShotRequest> = actor { consumeEach { request -> val espresso = processEspressoShot(request.groundBeans) request.deferredEspressoShot.complete(espresso) } } private val portafilterTwo: SendChannel<EspressoShotRequest> = actor {...} suspend fun pullEspressoShot(groundBeans: CoffeeBean.GroundBeans): Espresso { return select { portafilterOne.onSend(groundBeans) { TODO("sent to portafilter one - wait for result") } portafilterTwo.onSend(request) { TODO("sent to portafilter two - wait for result") } } } ... } https://jagstalk.page.link/examples
  51. class EspressoMachine { private data class EspressoShotRequest( val deferredEspressoShot: CompletableDeferred<Espresso>,

    val groundBeans: CoffeeBean.GroundBeans ) private val portafilterOne: SendChannel<EspressoShotRequest> = actor { consumeEach { request -> val espresso = processEspressoShot(request.groundBeans) request.deferredEspressoShot.complete(espresso) } } private val portafilterTwo: SendChannel<EspressoShotRequest> = actor {...} suspend fun pullEspressoShot(groundBeans: CoffeeBean.GroundBeans): Espresso { val request = EspressoShotRequest(CompletableDeferred(), groundBeans) return select { portafilterOne.onSend(request) { request.deferredEspressoShot.await() } portafilterTwo.onSend(request) { TODO("sent to portafilter two - wait for result") } } } ... } https://jagstalk.page.link/examples
  52. class EspressoMachine(scope: CoroutineScope): CoroutineScope by scope { private data class

    EspressoShotRequest( val deferredEspressoShot: CompletableDeferred<Espresso>, val groundBeans: CoffeeBean.GroundBeans ) private val portafilterOne: SendChannel<EspressoShotRequest> = actor { consumeEach { request -> val espresso = processEspressoShot(request.groundBeans) request.deferredEspressoShot.complete(espresso) } } private val portafilterTwo: SendChannel<EspressoShotRequest> = actor {...} suspend fun pullEspressoShot(groundBeans: CoffeeBean.GroundBeans): Espresso { val request = EspressoShotRequest(CompletableDeferred(), groundBeans) return select { portafilterOne.onSend(request) { request.deferredEspressoShot.await() } portafilterTwo.onSend(request) { TODO("sent to portafilter two - wait for result") } } } ... } https://jagstalk.page.link/examples
  53. class EspressoMachine(scope: CoroutineScope): CoroutineScope by scope { ... } fun

    main() = runBlocking { ... val espressoMachine = EspressoMachine(this) val time = measureTimeMillis { coroutineScope { launch(CoroutineName("barista-1")) { processOrders(ordersChannel, espressoMachine) } launch(CoroutineName("barista-2")) { processOrders(ordersChannel, espressoMachine) } } } log("time: $time ms") } private suspend fun processOrders(orders: ReceiveChannel<Menu.Cappuccino>, espressoMachine: EspressoMachine) { orders.consumeEach { val groundBeans = grindCoffeeBeans(it.beans()) val espresso = espressoMachine.pullEspressoShot(groundBeans) val steamedMilk = espressoMachine.steamMilk(it.milk()) val cappuccino = makeCappuccino(it, espresso, steamedMilk) log("serve: $cappuccino") } } https://jagstalk.page.link/examples
  54. private suspend fun processOrders(orders: ReceiveChannel<Menu.Cappuccino>, espressoMachine: EspressoMachine) { orders.consumeEach {

    val groundBeans = grindCoffeeBeans(it.beans()) val espressoDeferred = async { espressoMachine.pullEspressoShot(groundBeans) } val steamedMilkDeferred = async { espressoMachine.steamMilk(it.milk()) } val cappuccino = makeCappuccino( it, espresso, steamedMilk) log("serve: $cappuccino") } } https://jagstalk.page.link/examples
  55. private suspend fun processOrders(orders: ReceiveChannel<Menu.Cappuccino>, espressoMachine: EspressoMachine) { orders.consumeEach {

    val groundBeans = grindCoffeeBeans(it.beans()) val espressoDeferred = async { espressoMachine.pullEspressoShot(groundBeans) } val steamedMilkDeferred = async { espressoMachine.steamMilk(it.milk()) } val cappuccino = makeCappuccino( it, espressoDeferred.await(), steamedMilkDeferred.await()) log("serve: $cappuccino") } } https://jagstalk.page.link/examples
  56. private suspend fun processOrders(orders: ReceiveChannel<Menu.Cappuccino>, espressoMachine: EspressoMachine) { orders.consumeEach {

    val groundBeans = grindCoffeeBeans(it.beans()) coroutineScope { val espressoDeferred = async { espressoMachine.pullEspressoShot(groundBeans) } val steamedMilkDeferred = async { espressoMachine.steamMilk(it.milk()) } val cappuccino = makeCappuccino( it, espressoDeferred.await(), steamedMilkDeferred.await()) } log("serve: $cappuccino") } } https://jagstalk.page.link/examples
  57. Flow Channels are for Hot Streams Flow is for Cold

    Streams Flow is activated with collect https://jagstalk.page.link/examples
  58. https://jagstalk.page.link/examples fun main() = runBlocking { val orders = listOf(...)

    val ordersChannel = produce(CoroutineName("cashier")) { orders.forEach { send(it) } } val espressoMachine = EspressoMachine(this) val time = measureTimeMillis { coroutineScope { launch(CoroutineName("barista-1")) { processOrders(ordersChannel, espressoMachine) } launch(CoroutineName("barista-2")) { processOrders(ordersChannel, espressoMachine) } } } log("time: $time ms") espressoMachine.destroy() }
  59. https://jagstalk.page.link/examples fun main() = runBlocking { val orders = listOf(...)

    val ordersChannel = produce(CoroutineName("cashier")) { orders.forEach { send(it) } } val espressoMachine = EspressoMachine(this) val time = measureTimeMillis { coroutineScope { launch(CoroutineName("barista-1")) { processOrders(ordersChannel, espressoMachine) } launch(CoroutineName("barista-2")) { processOrders(ordersChannel, espressoMachine) } } } log("time: $time ms") espressoMachine.destroy() }
  60. https://jagstalk.page.link/examples fun main() = runBlocking { val orders = listOf(...)

    val ordersFlow: Flow<Menu.Cappuccino> = orders.asFlow() val espressoMachine = EspressoMachine(this) val time = measureTimeMillis { coroutineScope { launch(CoroutineName("barista-1")) { processOrders(ordersChannel, espressoMachine) } launch(CoroutineName("barista-2")) { processOrders(ordersChannel, espressoMachine) } } } log("time: $time ms") espressoMachine.destroy() }
  61. https://jagstalk.page.link/examples fun main() = runBlocking { val orders = listOf(...)

    val ordersFlow: Flow<Menu.Cappuccino> = orders.asFlow() val espressoMachine = EspressoMachine(this) val time = measureTimeMillis { coroutineScope { launch(CoroutineName("barista-1")) { processOrders(ordersChannel, espressoMachine) } launch(CoroutineName("barista-2")) { processOrders(ordersChannel, espressoMachine) } } } log("time: $time ms") espressoMachine.destroy() }
  62. https://jagstalk.page.link/examples private suspend fun processOrders(orders: ReceiveChannel<Menu.Cappuccino>, espressoMachine: EspressoMachine) { orders.consumeEach

    { val groundBeans = grindCoffeeBeans(it.beans()) coroutineScope { val espressoDeferred = async { espressoMachine.pullEspressoShot(groundBeans) } val steamedMilkDeferred = async { espressoMachine.steamMilk(it.milk()) } val cappuccino = makeCappuccino(it, espressoDeferred.await(), steamedMilkDeferred.await()) log("serve: $cappuccino") } } } fun main() = runBlocking { val orders = listOf(...) val ordersFlow: Flow<Menu.Cappuccino> = orders.asFlow() val espressoMachine = EspressoMachine(this) val time = measureTimeMillis { ... } log("time: $time ms") espressoMachine.destroy() }
  63. https://jagstalk.page.link/examples private suspend fun processOrders(orders: Flow<Menu.Cappuccino>, espressoMachine: EspressoMachine) { orders.consumeEach

    { val groundBeans = grindCoffeeBeans(it.beans()) coroutineScope { val espressoDeferred = async { espressoMachine.pullEspressoShot(groundBeans) } val steamedMilkDeferred = async { espressoMachine.steamMilk(it.milk()) } val cappuccino = makeCappuccino(it, espressoDeferred.await(), steamedMilkDeferred.await()) log("serve: $cappuccino") } } } fun main() = runBlocking { val orders = listOf(...) val ordersFlow: Flow<Menu.Cappuccino> = orders.asFlow() val espressoMachine = EspressoMachine(this) val time = measureTimeMillis { ... } log("time: $time ms") espressoMachine.destroy() }
  64. https://jagstalk.page.link/examples private suspend fun processOrders(orders: Flow<Menu.Cappuccino>, espressoMachine: EspressoMachine) { orders.consumeEach

    { val groundBeans = grindCoffeeBeans(it.beans()) coroutineScope { val espressoDeferred = async { espressoMachine.pullEspressoShot(groundBeans) } val steamedMilkDeferred = async { espressoMachine.steamMilk(it.milk()) } val cappuccino = makeCappuccino(it, espressoDeferred.await(), steamedMilkDeferred.await()) log("serve: $cappuccino") } } } fun main() = runBlocking { val orders = listOf(...) val ordersFlow: Flow<Menu.Cappuccino> = orders.asFlow() val espressoMachine = EspressoMachine(this) val time = measureTimeMillis { ... } log("time: $time ms") espressoMachine.destroy() }
  65. https://jagstalk.page.link/examples private suspend fun processOrders(orders: Flow<Menu.Cappuccino>, espressoMachine: EspressoMachine) { orders.map

    { val groundBeans = grindCoffeeBeans(it.beans()) coroutineScope { val espressoDeferred = async { espressoMachine.pullEspressoShot(groundBeans) } val steamedMilkDeferred = async { espressoMachine.steamMilk(it.milk()) } val cappuccino = makeCappuccino(it, espressoDeferred.await(), steamedMilkDeferred.await()) log("serve: $cappuccino") } } } fun main() = runBlocking { val orders = listOf(...) val ordersFlow: Flow<Menu.Cappuccino> = orders.asFlow() val espressoMachine = EspressoMachine(this) val time = measureTimeMillis { ... } log("time: $time ms") espressoMachine.destroy() }
  66. https://jagstalk.page.link/examples private suspend fun processOrders(orders: Flow<Menu.Cappuccino>, espressoMachine: EspressoMachine) { orders.map

    { val groundBeans = grindCoffeeBeans(it.beans()) coroutineScope { val espressoDeferred = async { espressoMachine.pullEspressoShot(groundBeans) } val steamedMilkDeferred = async { espressoMachine.steamMilk(it.milk()) } val cappuccino = makeCappuccino(it, espressoDeferred.await(), steamedMilkDeferred.await()) log("serve: $cappuccino") } } } fun main() = runBlocking { val orders = listOf(...) val ordersFlow: Flow<Menu.Cappuccino> = orders.asFlow() val espressoMachine = EspressoMachine(this) val time = measureTimeMillis { ... } log("time: $time ms") espressoMachine.destroy() }
  67. https://jagstalk.page.link/examples private suspend fun processOrders(orders: Flow<Menu.Cappuccino>, espressoMachine: EspressoMachine) { orders.map

    { val groundBeans = grindCoffeeBeans(it.beans()) coroutineScope { val espressoDeferred = async { espressoMachine.pullEspressoShot(groundBeans) } val steamedMilkDeferred = async { espressoMachine.steamMilk(it.milk()) } makeCappuccino(it, espressoDeferred.await(), steamedMilkDeferred.await()) } } } fun main() = runBlocking { val orders = listOf(...) val ordersFlow: Flow<Menu.Cappuccino> = orders.asFlow() val espressoMachine = EspressoMachine(this) val time = measureTimeMillis { ... } log("time: $time ms") espressoMachine.destroy() }
  68. https://jagstalk.page.link/examples private suspend fun processOrders(orders: Flow<Menu.Cappuccino>, espressoMachine: EspressoMachine): Flow<Beverage.Cappuccino> =

    orders.map { val groundBeans = grindCoffeeBeans(it.beans()) coroutineScope { val espressoDeferred = async { espressoMachine.pullEspressoShot(groundBeans) } val steamedMilkDeferred = async { espressoMachine.steamMilk(it.milk()) } makeCappuccino(it, espressoDeferred.await(), steamedMilkDeferred.await()) } } fun main() = runBlocking { val orders = listOf(...) val ordersFlow: Flow<Menu.Cappuccino> = orders.asFlow() val espressoMachine = EspressoMachine(this) val time = measureTimeMillis { ... } log("time: $time ms") espressoMachine.destroy() }
  69. https://jagstalk.page.link/examples private suspend fun processOrders(orders: Flow<Menu.Cappuccino>, espressoMachine: EspressoMachine): Flow<Beverage.Cappuccino> {

    ...
 } fun main() = runBlocking { val orders = listOf(...) val ordersFlow: Flow<Menu.Cappuccino> = orders.asFlow() val espressoMachine = EspressoMachine(this) val time = measureTimeMillis { coroutineScope { launch(CoroutineName("barista-1")) { processOrders(ordersChannel, espressoMachine) } launch(CoroutineName("barista-2")) { processOrders(ordersChannel, espressoMachine) } } } log("time: $time ms") espressoMachine.destroy() }
  70. https://jagstalk.page.link/examples private suspend fun processOrders(orders: Flow<Menu.Cappuccino>, espressoMachine: EspressoMachine): Flow<Beverage.Cappuccino> {

    ...
 } fun main() = runBlocking { val orders = listOf(...) val ordersFlow: Flow<Menu.Cappuccino> = orders.asFlow() val espressoMachine = EspressoMachine(this) val time = measureTimeMillis { flowOf( processOrders(ordersFlow, espressoMachine), processOrders(ordersFlow, espressoMachine) ) } log("time: $time ms") espressoMachine.destroy() }
  71. https://jagstalk.page.link/examples private suspend fun processOrders(orders: Flow<Menu.Cappuccino>, espressoMachine: EspressoMachine): Flow<Beverage.Cappuccino> {

    ...
 } fun main() = runBlocking { val orders = listOf(...) val ordersFlow: Flow<Menu.Cappuccino> = orders.asFlow() val espressoMachine = EspressoMachine(this) val time = measureTimeMillis { flowOf( processOrders(ordersFlow, espressoMachine), processOrders(ordersFlow, espressoMachine) ) .flattenMerge() } log("time: $time ms") espressoMachine.destroy() }
  72. https://jagstalk.page.link/examples private suspend fun processOrders(orders: Flow<Menu.Cappuccino>, espressoMachine: EspressoMachine): Flow<Beverage.Cappuccino> {

    ...
 } fun main() = runBlocking { val orders = listOf(...) val ordersFlow: Flow<Menu.Cappuccino> = orders.asFlow() val espressoMachine = EspressoMachine(this) val time = measureTimeMillis { flowOf( processOrders(ordersFlow, espressoMachine), processOrders(ordersFlow, espressoMachine) ) .flattenMerge() .collect { cappuccino -> log("serve: $cappuccino") } } log("time: $time ms") espressoMachine.destroy() }
  73. https://jagstalk.page.link/examples fun main() = runBlocking { val orders = listOf(...)

    val ordersFlow: Flow<Menu.Cappuccino> = orders.asFlow() .produceIn(this) .asFlow() val espressoMachine = EspressoMachine(this) val time = measureTimeMillis { flowOf( processOrders(ordersFlow, espressoMachine), processOrders(ordersFlow, espressoMachine) ) .flattenMerge() .collect { cappuccino -> log("serve: $cappuccino") } } log("time: $time ms") espressoMachine.destroy() }
  74. https://jagstalk.page.link/examples fun main() = runBlocking { val orders = listOf(...)

    val ordersFlow: Flow<Menu.Cappuccino> = orders.asFlow() .produceIn(this) .asFlow() val espressoMachine = EspressoMachine(this) val time = measureTimeMillis { flowOf( processOrders(ordersFlow, espressoMachine), processOrders(ordersFlow, espressoMachine) ) .flattenMerge() .collect { cappuccino -> log("serve: $cappuccino") } } log("time: $time ms") espressoMachine.destroy() } private fun <T> ReceiveChannel<T>.asFlow(): Flow<T> = flow { consumeEach { value -> emit(value) } }