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

Fresh Async with Kotlin

Fresh Async with Kotlin

Introduction to Kotlin Coroutines for a stable released version with Kotlin 1.3. It covers various async programming styles -- callbacks, futures/promises, and Kotlin suspending functions that are easiest to use of all. It shows integration of Kotlin coroutines with a zoo of futures on JVM, compares them with async/await from other languages, introduces structured concurrency and gives a glimpse of CSP. Presented at GOTO Copenhagen 2018.

F9c354e780ce562daea0e21b99bfdc0d?s=128

Roman Elizarov

November 20, 2018
Tweet

More Decks by Roman Elizarov

Other Decks in Programming

Transcript

  1. Fresh Async with Kotlin Roman Elizarov

  2. Speaker: Roman Elizarov • Professional developer since 2000 • Previously

    developed high-perf trading software @ Devexperts • Teach concurrent & distributed programming @ St. Petersburg ITMO University • Chief judge @ Northern Eurasia Contest / ACM ICPC • Now team lead in Kotlin Libraries @ JetBrains
  3. History Simula’67 Coroutines CLU’75 Icon’77 Generators C’72 C++’85 Java’95 C#’00

    Kotlin’11 C#’12 async/await Kotlin 1.1 (‘17) Coroutines Exp. C++20? Java XX? Threads Asynchronous Programming Microservices Kotlin 1.3 (‘18) Coroutines Release Erlang’86 Go’09
  4. Asynchronous Programming with Callbacks

  5. Callbacks: before fun requestToken(): Token { // makes request for

    a token & waits return token // returns result when received } 1
  6. Callbacks: after fun requestTokenAsync(cb: (Token) -> Unit) { // makes

    request for a token, invokes callback when done // returns immediately } 1 callback
  7. Callbacks: before fun requestTokenAsync(cb: (Token) -> Unit) { … }

    fun createPost(token: Token, item: Item): Post { // sends item to the server & waits return post // returns resulting post } 2
  8. Callbacks: after fun requestTokenAsync(cb: (Token) -> Unit) { … }

    fun createPostAsync(token: Token, item: Item, cb: (Post) -> Unit) { // sends item to the server, invokes callback when done // returns immediately } 2 callback
  9. Callbacks: before fun requestTokenAsync(cb: (Token) -> Unit) { … }

    fun createPostAsync(token: Token, item: Item, cb: (Post) -> Unit) { … } fun processPost(post: Post) { … } fun postItem(item: Item) { val token = requestToken() val post = createPost(token, item) processPost(post) }
  10. Callbacks: after fun requestTokenAsync(cb: (Token) -> Unit) { … }

    fun createPostAsync(token: Token, item: Item, cb: (Post) -> Unit) { … } fun processPost(post: Post) { … } fun postItem(item: Item) { requestTokenAsync { token -> createPostAsync(token, item) { post -> processPost(post) } } } aka “callback hell” This is simplified. Handling exceptions makes it a real mess
  11. Futures/Promises make it nicer

  12. Futures: before fun requestTokenAsync(cb: (Token) -> Unit) { // makes

    request for a token, invokes callback when done // returns immediately } 1
  13. Futures: after fun requestTokenAsync(): Promise<Token> { // makes request for

    a token // returns promise for a future result immediately } 1 future
  14. Futures: before fun requestTokenAsync(): Promise<Token> { … } fun createPostAsync(token:

    Token, item: Item, cb: (Post) -> Unit) { // sends item to the server, invokes callback when done // returns immediately } 2
  15. Futures: after fun requestTokenAsync(): Promise<Token> { … } fun createPostAsync(token:

    Token, item: Item): Promise<Post> { // sends item to the server // returns promise for a future result immediately } future 2
  16. Futures: before fun requestTokenAsync(): Promise<Token> { … } fun createPostAsync(token:

    Token, item: Item): Promise<Post> … fun processPost(post: Post) { … } fun postItem(item: Item) { requestTokenAsync { token -> createPostAsync(token, item) { post -> processPost(post) } } }
  17. Futures: after fun requestTokenAsync(): Promise<Token> { … } fun createPostAsync(token:

    Token, item: Item): Promise<Post> … fun processPost(post: Post) { … } fun postItem(item: Item) { requestTokenAsync() .thenCompose { token -> createPostAsync(token, item) } .thenAccept { post -> processPost(post) } }
  18. Futures: after fun requestTokenAsync(): Promise<Token> { … } fun createPostAsync(token:

    Token, item: Item): Promise<Post> … fun processPost(post: Post) { … } fun postItem(item: Item) { requestTokenAsync() .thenCompose { token -> createPostAsync(token, item) } .thenAccept { post -> processPost(post) } } Callbacks are still here
  19. Futures: after fun requestTokenAsync(): Promise<Token> { … } fun createPostAsync(token:

    Token, item: Item): Promise<Post> … fun processPost(post: Post) { … } fun postItem(item: Item) { requestTokenAsync() .thenCompose { token -> createPostAsync(token, item) } .thenAccept { post -> processPost(post) } } Composable & propagates exceptions No nesting indentation Callbacks are still here
  20. Futures: after fun requestTokenAsync(): Promise<Token> { … } fun createPostAsync(token:

    Token, item: Item): Promise<Post> … fun processPost(post: Post) { … } fun postItem(item: Item) { requestTokenAsync() .thenCompose { token -> createPostAsync(token, item) } .thenAccept { post -> processPost(post) } } But all those operators…
  21. Kotlin coroutines to the rescue

  22. Coroutines: before fun requestTokenAsync(): Promise<Token> { // makes request for

    a token // returns promise for a future result immediately } 1
  23. Coroutines: after suspend fun requestToken(): Token { // makes request

    for a token & suspends return token // returns result when received } 1 natural signature
  24. Coroutines: before suspend fun requestToken(): Token { … } fun

    createPostAsync(token: Token, item: Item): Promise<Post> { // sends item to the server // returns promise for a future result immediately } 2
  25. Coroutines: after suspend fun requestToken(): Token { … } suspend

    fun createPost(token: Token, item: Item): Post { // sends item to the server & suspends return post // returns result when received } 2 natural signature
  26. Coroutines: before suspend fun requestToken(): Token { … } suspend

    fun createPost(token: Token, item: Item): Post { … } fun processPost(post: Post) { … } fun postItem(item: Item) { requestTokenAsync() .thenCompose { token -> createPostAsync(token, item) } .thenAccept { post -> processPost(post) } }
  27. Coroutines: after suspend fun requestToken(): Token { … } suspend

    fun createPost(token: Token, item: Item): Post { … } fun processPost(post: Post) { … } suspend fun postItem(item: Item) { val token = requestToken() val post = createPost(token, item) processPost(post) }
  28. Coroutines: after suspend fun requestToken(): Token { … } suspend

    fun createPost(token: Token, item: Item): Post { … } fun processPost(post: Post) { … } suspend fun postItem(item: Item) { val token = requestToken() val post = createPost(token, item) processPost(post) } Like regular code
  29. Coroutines: after suspend fun requestToken(): Token { … } suspend

    fun createPost(token: Token, item: Item): Post { … } fun processPost(post: Post) { … } suspend fun postItem(item: Item) { val token = requestToken() val post = createPost(token, item) processPost(post) } suspension points
  30. • Regular loops Bonus features for ((token, item) in list)

    { createPost(token, item) }
  31. • Regular exception handing Bonus features try { createPost(token, item)

    } catch (e: BadTokenException) { … }
  32. • Regular higher-order functions Bonus features file.readLines().forEach { line ->

    createPost(token, line.toItem()) }
  33. • Custom higher-order functions Bonus features val post = retryIO

    { createPost(token, item) } Everything like in regular code
  34. How does it work? A quick peek behind the scenes

  35. Kotlin suspending functions callback Kotlin Java/JVM suspend fun createPost(token: Token,

    item: Item): Post { … } Object createPost(Token token, Item item, Continuation<Post> cont) { … }
  36. Kotlin suspending functions callback Kotlin Java/JVM Continuation is a generic

    callback interface suspend fun createPost(token: Token, item: Item): Post { … } Object createPost(Token token, Item item, Continuation<Post> cont) { … } interface Continuation<in T> { val context: CoroutineContext fun resumeWith(result: Result<T>) }
  37. Kotlin suspending functions callback Kotlin Java/JVM suspend fun createPost(token: Token,

    item: Item): Post { … } Object createPost(Token token, Item item, Continuation<Post> cont) { … } interface Continuation<in T> { val context: CoroutineContext fun resumeWith(result: Result<T>) }
  38. Kotlin suspending functions callback Kotlin Java/JVM suspend fun createPost(token: Token,

    item: Item): Post { … } Object createPost(Token token, Item item, Continuation<Post> cont) { … } interface Continuation<in T> { val context: CoroutineContext fun resumeWith(result: Result<T>) }
  39. Integration Zoo of futures on JVM

  40. interface Service { fun createPost(token: Token, item: Item): Call<Post> }

    Retrofit async
  41. interface Service { fun createPost(token: Token, item: Item): Call<Post> }

    suspend fun createPost(token: Token, item: Item): Post = serviceInstance.createPost(token, item).await() natural signature
  42. interface Service { fun createPost(token: Token, item: Item): Call<Post> }

    suspend fun createPost(token: Token, item: Item): Post = serviceInstance.createPost(token, item).await() Suspending extension function from integration library
  43. suspend fun <T> Call<T>.await(): T { … }

  44. Callbacks everywhere suspend fun <T> Call<T>.await(): T { enqueue(object :

    Callback<T> { override fun onResponse(call: Call<T>, response: Response<T>) { // todo } override fun onFailure(call: Call<T>, t: Throwable) { // todo } }) }
  45. suspend fun <T> Call<T>.await(): T = suspendCoroutine { cont ->

    enqueue(object : Callback<T> { override fun onResponse(call: Call<T>, response: Response<T>) { if (response.isSuccessful) cont.resume(response.body()!!) else cont.resumeWithException(ErrorResponse(response)) } override fun onFailure(call: Call<T>, t: Throwable) { cont.resumeWithException(t) } }) }
  46. suspend fun <T> suspendCoroutine(block: (Continuation<T>) -> Unit): T

  47. suspend fun <T> suspendCoroutine(block: (Continuation<T>) -> Unit): T

  48. suspend fun <T> suspendCoroutine(block: (Continuation<T>) -> Unit): T Regular function

    Inspired by call/cc from Scheme
  49. suspend fun <T> Call<T>.await(): T = suspendCoroutine { cont ->

    enqueue(object : Callback<T> { override fun onResponse(call: Call<T>, response: Response<T>) { if (response.isSuccessful) cont.resume(response.body()!!) else cont.resumeWithException(ErrorResponse(response)) } override fun onFailure(call: Call<T>, t: Throwable) { cont.resumeWithException(t) } }) }
  50. Install callback suspend fun <T> Call<T>.await(): T = suspendCoroutine {

    cont -> enqueue(object : Callback<T> { override fun onResponse(call: Call<T>, response: Response<T>) { if (response.isSuccessful) cont.resume(response.body()!!) else cont.resumeWithException(ErrorResponse(response)) } override fun onFailure(call: Call<T>, t: Throwable) { cont.resumeWithException(t) } }) }
  51. Install callback suspend fun <T> Call<T>.await(): T = suspendCoroutine {

    cont -> enqueue(object : Callback<T> { override fun onResponse(call: Call<T>, response: Response<T>) { if (response.isSuccessful) cont.resume(response.body()!!) else cont.resumeWithException(ErrorResponse(response)) } override fun onFailure(call: Call<T>, t: Throwable) { cont.resumeWithException(t) } }) }
  52. Analyze response suspend fun <T> Call<T>.await(): T = suspendCoroutine {

    cont -> enqueue(object : Callback<T> { override fun onResponse(call: Call<T>, response: Response<T>) { if (response.isSuccessful) cont.resume(response.body()!!) else cont.resumeWithException(ErrorResponse(response)) } override fun onFailure(call: Call<T>, t: Throwable) { cont.resumeWithException(t) } }) }
  53. Analyze response suspend fun <T> Call<T>.await(): T = suspendCoroutine {

    cont -> enqueue(object : Callback<T> { override fun onResponse(call: Call<T>, response: Response<T>) { if (response.isSuccessful) cont.resume(response.body()!!) else cont.resumeWithException(ErrorResponse(response)) } override fun onFailure(call: Call<T>, t: Throwable) { cont.resumeWithException(t) } }) } That’s all
  54. Coroutine builders

  55. Coroutines revisited suspend fun requestToken(): Token { … } suspend

    fun createPost(token: Token, item: Item): Post { … } fun processPost(post: Post) { … } suspend fun postItem(item: Item) { val token = requestToken() val post = createPost(token, item) processPost(post) }
  56. Coroutines revisited suspend fun requestToken(): Token { … } suspend

    fun createPost(token: Token, item: Item): Post { … } fun processPost(post: Post) { … } fun postItem(item: Item) { val token = requestToken() val post = createPost(token, item) processPost(post) }
  57. Coroutines revisited suspend fun requestToken(): Token { … } suspend

    fun createPost(token: Token, item: Item): Post { … } fun processPost(post: Post) { … } fun postItem(item: Item) { val token = requestToken() val post = createPost(token, item) processPost(post) } Error: Suspend function 'requestToken' should be called only from a coroutine or another suspend function
  58. Coroutines revisited suspend fun requestToken(): Token { … } suspend

    fun createPost(token: Token, item: Item): Post { … } fun processPost(post: Post) { … } fun postItem(item: Item) { val token = requestToken() val post = createPost(token, item) processPost(post) } Can suspend execution
  59. Coroutines revisited suspend fun requestToken(): Token { … } suspend

    fun createPost(token: Token, item: Item): Post { … } fun processPost(post: Post) { … } fun postItem(item: Item) { val token = requestToken() val post = createPost(token, item) processPost(post) } Can suspend execution A regular function cannot
  60. Coroutines revisited suspend fun requestToken(): Token { … } suspend

    fun createPost(token: Token, item: Item): Post { … } fun processPost(post: Post) { … } fun postItem(item: Item) { val token = requestToken() val post = createPost(token, item) processPost(post) } Can suspend execution A regular function cannot One cannot simply invoke a suspending function
  61. Launch fun postItem(item: Item) { GlobalScope.launch { val token =

    requestToken() val post = createPost(token, item) processPost(post) } } coroutine builder
  62. fun postItem(item: Item) { GlobalScope.launch { val token = requestToken()

    val post = createPost(token, item) processPost(post) } } Fire and forget!
  63. fun postItem(item: Item) { GlobalScope.launch { val token = requestToken()

    val post = createPost(token, item) processPost(post) } } Fire and forget! We launch for its side effects
  64. fun postItem(item: Item) { GlobalScope.launch { val token = requestToken()

    val post = createPost(token, item) processPost(post) } } Returns immediately, coroutine works in background thread pool
  65. fun postItem(item: Item) { GlobalScope.launch { val token = requestToken()

    val post = createPost(token, item) processPost(post) } }
  66. fun postItem(item: Item) { GlobalScope.launch(Dispatchers.Main) { val token = requestToken()

    val post = createPost(token, item) processPost(post) } } Dispatcher Just specify the dispatcher
  67. fun postItem(item: Item) { GlobalScope.launch(Dispatchers.Main) { val token = requestToken()

    val post = createPost(token, item) processPost(post) } } Dispatcher And it gets executed on the Main thread
  68. Where’s the magic of launch?

  69. fun CoroutineScope.launch( context: CoroutineContext = EmptyCoroutineContext, block: suspend () ->

    Unit ): Job { … } A regular function
  70. fun CoroutineScope.launch( context: CoroutineContext = EmptyCoroutineContext, block: suspend () ->

    Unit ): Job { … } suspending lambda
  71. fun CoroutineScope.launch( context: CoroutineContext = EmptyCoroutineContext, block: suspend () ->

    Unit ): Job { … }
  72. async / await The classic approach

  73. Kotlin-way suspend fun postItem(item: Item) { val token = requestToken()

    val post = createPost(token, item) processPost(post) } Kotlin suspend fun requestToken(): Token { … } suspend fun createPost(token: Token, item: Item): Post { … } fun processPost(post: Post) { … }
  74. async Task postItem(Item item) { var token = await requestToken();

    var post = await createPost(token, item); processPost(post); } Classic-way C# approach to the same problem (also Python, TS, Dart, coming to JS) C# async Task<Token> requestToken() { … } async Task<Post> createPost(Token token, Item item) { … } void processPost(Post post) { … }
  75. async Task postItem(Item item) { var token = await requestToken();

    var post = await createPost(token, item); processPost(post); } Classic-way mark with async C# async Task<Token> requestToken() { … } async Task<Post> createPost(Token token, Item item) { … } void processPost(Post post) { … }
  76. async Task postItem(Item item) { var token = await requestToken();

    var post = await createPost(token, item); processPost(post); } Classic-way use await to suspend C# async Task<Token> requestToken() { … } async Task<Post> createPost(Token token, Item item) { … } void processPost(Post post) { … }
  77. async Task postItem(Item item) { var token = await requestToken();

    var post = await createPost(token, item); processPost(post); } Classic-way C# returns a future async Task<Token> requestToken() { … } async Task<Post> createPost(Token token, Item item) { … } void processPost(Post post) { … }
  78. Why no await keyword in Kotlin? The problem with async

    requestToken() VALID –> produces Task<Token> await requestToken() VALID –> produces Token concurrent behavior sequential behavior C# C# default
  79. Kotlin suspending functions are designed to imitate sequential behavior by

    default Concurrency is hard Concurrency has to be explicit
  80. Kotlin approach to async Concurrency where you need it

  81. Use-case for async async Task<Image> loadImageAsync(String name) { … }

    C#
  82. Use-case for async var promise1 = loadImageAsync(name1); var promise2 =

    loadImageAsync(name2); async Task<Image> loadImageAsync(String name) { … } Start multiple operations concurrently C#
  83. Use-case for async var promise1 = loadImageAsync(name1); var promise2 =

    loadImageAsync(name2); var image1 = await promise1; var image2 = await promise2; async Task<Image> loadImageAsync(String name) { … } and then wait for them C#
  84. Use-case for async var result = combineImages(image1, image2); C# var

    promise1 = loadImageAsync(name1); var promise2 = loadImageAsync(name2); var image1 = await promise1; var image2 = await promise2; async Task<Image> loadImageAsync(String name) { … }
  85. Kotlin async function fun loadImageAsync(name: String): Deferred<Image> = GlobalScope.async {

    … } Kotlin
  86. Kotlin async function fun loadImageAsync(name: String): Deferred<Image> = GlobalScope.async {

    … } Kotlin A regular function
  87. Kotlin async function fun loadImageAsync(name: String): Deferred<Image> = GlobalScope.async {

    … } Kotlin’s future type Kotlin
  88. Kotlin async function fun loadImageAsync(name: String): Deferred<Image> = GlobalScope.async {

    … } async coroutine builder Kotlin
  89. fun loadImageAsync(name: String): Deferred<Image> = GlobalScope.async { … } val

    deferred1 = loadImageAsync(name1) val deferred2 = loadImageAsync(name2) Start multiple operations concurrently Kotlin
  90. fun loadImageAsync(name: String): Deferred<Image> = GlobalScope.async { … } val

    deferred1 = loadImageAsync(name1) val deferred2 = loadImageAsync(name2) val image1 = deferred1.await() val image2 = deferred2.await() and then wait for them await function Suspends until deferred is complete Kotlin
  91. fun loadImageAsync(name: String): Deferred<Image> = GlobalScope.async { … } val

    deferred1 = loadImageAsync(name1) val deferred2 = loadImageAsync(name2) val image1 = deferred1.await() val image2 = deferred2.await() val result = combineImages(image1, image2) Kotlin But what if this crashes? Crash?
  92. fun loadImageAsync(name: String): Deferred<Image> = GlobalScope.async { … } val

    deferred1 = loadImageAsync(name1) val deferred2 = loadImageAsync(name2) val image1 = deferred1.await() val image2 = deferred2.await() val result = combineImages(image1, image2) Kotlin Crash? This one leaks But what if this crashes?
  93. Idiomatic: Using async function when needed suspend fun loadImage(name: String):

    Image { … } Is defined as suspending function, not async
  94. Idiomatic: Using async function when needed suspend fun loadImage(name: String):

    Image { … } suspend fun loadAndCombine(name1: String, name2: String): Image = coroutineScope { val deferred1 = async { loadImage(name1) } val deferred2 = async { loadImage(name2) } combineImages(deferred1.await(), deferred2.await()) } Structured concurrency
  95. Idiomatic: Using async function when needed suspend fun loadImage(name: String):

    Image { … } suspend fun loadAndCombine(name1: String, name2: String): Image = coroutineScope { val deferred1 = async { loadImage(name1) } val deferred2 = async { loadImage(name2) } combineImages(deferred1.await(), deferred2.await()) }
  96. Idiomatic: Using async function when needed suspend fun loadImage(name: String):

    Image { … } suspend fun loadAndCombine(name1: String, name2: String): Image = coroutineScope { val deferred1 = async { loadImage(name1) } val deferred2 = async { loadImage(name2) } combineImages(deferred1.await(), deferred2.await()) }
  97. Idiomatic: Using async function when needed suspend fun loadImage(name: String):

    Image { … } suspend fun loadAndCombine(name1: String, name2: String): Image = coroutineScope { val deferred1 = async { loadImage(name1) } val deferred2 = async { loadImage(name2) } combineImages(deferred1.await(), deferred2.await()) }
  98. Kotlin approach to async requestToken() VALID –> produces Token async

    { requestToken() } VALID –> produces Deferred<Token> sequential behavior concurrent behavior Kotlin Kotlin default
  99. Structured concurrency

  100. Structured concurrency suspend fun loadImage(name: String): Image { … }

    suspend fun loadAndCombine(name1: String, name2: String): Image = coroutineScope { val deferred1 = async { loadImage(name1) } val deferred2 = async { loadImage(name2) } combineImages(deferred1.await(), deferred2.await()) }
  101. Crash suspend fun loadImage(name: String): Image { … } suspend

    fun loadAndCombine(name1: String, name2: String): Image = coroutineScope { val deferred1 = async { loadImage(name1) } val deferred2 = async { loadImage(name2) } combineImages(deferred1.await(), deferred2.await()) } Crashes?
  102. Cancels scope suspend fun loadImage(name: String): Image { … }

    suspend fun loadAndCombine(name1: String, name2: String): Image = coroutineScope { val deferred1 = async { loadImage(name1) } val deferred2 = async { loadImage(name2) } combineImages(deferred1.await(), deferred2.await()) } Cancels
  103. Cancels children suspend fun loadImage(name: String): Image { … }

    suspend fun loadAndCombine(name1: String, name2: String): Image = coroutineScope { val deferred1 = async { loadImage(name1) } val deferred2 = async { loadImage(name2) } combineImages(deferred1.await(), deferred2.await()) } Cancels
  104. Kotlin suspending functions may use concurrency internally, but don’t leak

    it Concurrency needs to be structured
  105. Parallelism is optional

  106. Beyond asynchronous code Kotlin’s approach to generate/yield – synchronous coroutines

  107. Fibonacci sequence val fibonacci: Sequence<Int> = …

  108. Fibonacci sequence val fibonacci = sequence { var cur =

    1 var next = 1 while (true) { yield(cur) val tmp = cur + next cur = next next = tmp } }
  109. Fibonacci sequence val fibonacci = sequence { var cur =

    1 var next = 1 while (true) { yield(cur) val tmp = cur + next cur = next next = tmp } } println(fibonacci.take(10).toList())
  110. Fibonacci sequence val fibonacci = sequence { var cur =

    1 var next = 1 while (true) { yield(cur) val tmp = cur + next cur = next next = tmp } } println(fibonacci.take(10).toList()) >> [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
  111. Fibonacci sequence val fibonacci = sequence { var cur =

    1 var next = 1 while (true) { yield(cur) val tmp = cur + next cur = next next = tmp } } A coroutine builder with restricted suspension
  112. Fibonacci sequence val fibonacci = sequence { var cur =

    1 var next = 1 while (true) { yield(cur) val tmp = cur + next cur = next next = tmp } } A suspending function in the scope of buildSequence
  113. Fibonacci sequence val fibonacci = sequence { var cur =

    1 var next = 1 while (true) { yield(cur) val tmp = cur + next cur = next next = tmp } } println(fibonacci.take(10).toList()) Synchronous
  114. Fibonacci sequence val fibonacci = sequence { var cur =

    1 var next = 1 while (true) { yield(cur) val tmp = cur + next cur = next next = tmp } } val iter = fibonacci.iterator()
  115. Fibonacci sequence val fibonacci = sequence { var cur =

    1 var next = 1 while (true) { yield(cur) val tmp = cur + next cur = next next = tmp } } val iter = fibonacci.iterator() println(iter.next())
  116. Fibonacci sequence val fibonacci = sequence { var cur =

    1 var next = 1 while (true) { yield(cur) val tmp = cur + next cur = next next = tmp } } val iter = fibonacci.iterator() println(iter.next())
  117. Fibonacci sequence val fibonacci = sequence { var cur =

    1 var next = 1 while (true) { yield(cur) val tmp = cur + next cur = next next = tmp } } val iter = fibonacci.iterator() println(iter.next())
  118. Fibonacci sequence val fibonacci = sequence { var cur =

    1 var next = 1 while (true) { yield(cur) val tmp = cur + next cur = next next = tmp } } val iter = fibonacci.iterator() println(iter.next())
  119. Fibonacci sequence val fibonacci = sequence { var cur =

    1 var next = 1 while (true) { yield(cur) val tmp = cur + next cur = next next = tmp } } val iter = fibonacci.iterator() println(iter.next()) // 1
  120. Fibonacci sequence val fibonacci = sequence { var cur =

    1 var next = 1 while (true) { yield(cur) val tmp = cur + next cur = next next = tmp } } val iter = fibonacci.iterator() println(iter.next()) // 1 println(iter.next())
  121. Fibonacci sequence val fibonacci = sequence { var cur =

    1 var next = 1 while (true) { yield(cur) val tmp = cur + next cur = next next = tmp } } val iter = fibonacci.iterator() println(iter.next()) // 1 println(iter.next())
  122. Fibonacci sequence val fibonacci = sequence { var cur =

    1 var next = 1 while (true) { yield(cur) val tmp = cur + next cur = next next = tmp } } val iter = fibonacci.iterator() println(iter.next()) // 1 println(iter.next())
  123. Fibonacci sequence val fibonacci = sequence { var cur =

    1 var next = 1 while (true) { yield(cur) val tmp = cur + next cur = next next = tmp } } val iter = fibonacci.iterator() println(iter.next()) // 1 println(iter.next())
  124. Fibonacci sequence val fibonacci = sequence { var cur =

    1 var next = 1 while (true) { yield(cur) val tmp = cur + next cur = next next = tmp } } val iter = fibonacci.iterator() println(iter.next()) // 1 println(iter.next())
  125. Fibonacci sequence val fibonacci = sequence { var cur =

    1 var next = 1 while (true) { yield(cur) val tmp = cur + next cur = next next = tmp } } val iter = fibonacci.iterator() println(iter.next()) // 1 println(iter.next()) // 1
  126. Fibonacci sequence val fibonacci = sequence { var cur =

    1 var next = 1 while (true) { yield(cur) val tmp = cur + next cur = next next = tmp } } val iter = fibonacci.iterator() println(iter.next()) // 1 println(iter.next()) // 1 etc ad infinum
  127. Sharing state?

  128. Shared Mutable State Operations Operations Operations

  129. Shared Mutable State Operations Operations Operations Needs synchronization

  130. Shared Mutable State @stefanobaghino

  131. Communicating Sequential Processes

  132. Concurrent Fibonacci sequence val fibonacci = GlobalScope.produce { var cur

    = 1 var next = 1 while (true) { send(cur) val tmp = cur + next cur = next next = tmp } } Asynchronous (can be in different thread)
  133. Concurrent Fibonacci sequence val fibonacci = GlobalScope.produce { var cur

    = 1 var next = 1 while (true) { send(cur) val tmp = cur + next cur = next next = tmp } } fun main(args: Array<String>) = runBlocking { println(fibonacci.receive()) } Another coroutine Asynchronous (can be in different thread)
  134. Concurrent Fibonacci sequence val fibonacci = GlobalScope.produce { var cur

    = 1 var next = 1 while (true) { send(cur) val tmp = cur + next cur = next next = tmp } } fun main(args: Array<String>) = runBlocking { println(fibonacci.receive()) } Another coroutine Receives from channel Asynchronous (can be in different thread)
  135. Concurrent Fibonacci sequence val fibonacci = GlobalScope.produce { var cur

    = 1 var next = 1 while (true) { send(cur) val tmp = cur + next cur = next next = tmp } } fun main(args: Array<String>) = runBlocking { println(fibonacci.receive()) // 1 }
  136. Concurrent Fibonacci sequence val fibonacci = GlobalScope.produce { var cur

    = 1 var next = 1 while (true) { send(cur) val tmp = cur + next cur = next next = tmp } } fun main(args: Array<String>) = runBlocking { println(fibonacci.receive()) // 1 println(fibonacci.receive()) // 1 } etc ad infinum
  137. Library vs Language Keeping the core language small

  138. Classic async async/await generate/yield Keywords

  139. Kotlin coroutines suspend Modifier

  140. Kotlin coroutines Standard library

  141. Kotlin coroutines Standard library kotlinx-coroutines launch, async, runBlocking, Job, Deferred,

    etc http://github.com/kotlin/kotlinx.coroutines
  142. None
  143. Thank you Any questions? elizarov @ Roman Elizarov relizarov

  144. None