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

Kotlin Coroutines

Avatar for Svetlana Isakova Svetlana Isakova
May 09, 2017
780

Kotlin Coroutines

Introduction to coroutines in Kotlin
presented at MCE

Avatar for Svetlana Isakova

Svetlana Isakova

May 09, 2017
Tweet

Transcript

  1. The Kotlin programming language • Releases: • Kotlin 1.0 -

    February 2016 • Kotlin 1.1 - March 2017 • Used in JetBrains • Used in Expedia, NBC News, Digital, Netflix, Amex, Pinterest, and others
  2. Kotlin Coroutines • the key new feature in Kotlin 1.1

    • brings the support of: • async/await, • yield, • and more
  3. Coroutine a main routine and a subroutine vs coroutines, which

    call on each other • the term from 1960s • was used in “The Art of Computer Programming” by Donald Knuth
  4. loadImageAsync().whenComplete { image -> panel.setImage(image) } async { val image

    = loadImageAsync(url).await() myUI.setImage(image) }
  5. C# way async Task<Image> LoadImageAsync(String url) { /* do the

    work */ } Kotlin way fun loadImageAsync() = async { /* do the work */ }
  6. C# way async Task ProcessImage(String url) { var image =

    await LoadImage(url); myUI.SetImage(image); } Kotlin way fun processImage() = async { val image = loadImageAsync().await() myUI.setImage(image) }
  7. Executor • fixed number of threads • adding tasks •

    but: difficult to manage dependencies
  8. 1 2 3 • computation that can be suspended •

    thread is not blocking! Coroutines
  9. suspending call Back to image example fun loadImageAsync() = async

    { /* do the work */ } fun processImage() = async { val image = loadImageAsync().await() myUI.setImage(image) }
  10. fun loadImageAsync(): Deferred<Image> = async { /* do the work

    */ } interface Deferred<out T> {
 suspend fun await(): T
 } await is a suspend function
  11. fun processImage() = async { val image = loadImageAsync().await() myUI.setImage(image)

    } await suspends computation loadImageAsync processImage processImage loadImageAsync 1 2 await
  12. fun processImage() = async(UI) {
 val deferred = loadImageAsync()
 //

    do other work
 val image = deferred.await() showImage(image)
 } Suspension might not happen if the result is already available processImage loadImageAsync await 1 2 processImage loadImageAsync
  13. fun overlay(first: Image, second: Image): Image fun overlayAsync() = async(CommonPool)

    {
 val first = loadImageAsync("green")
 val second = loadImageAsync("red")
 overlay(first.await(), second.await())
 } Image overlay: two asynchronous computations
  14. fun overlayAsync() = async(CommonPool) {
 val first = loadImageAsync("green")
 val

    second = loadImageAsync("red")
 overlay(first.await(), second.await())
 } button.onClick {
 launch(UI) {
 val image = overlayAsync().await()
 showImage(image)
 }
 } Image overlay
  15. await rethrows exceptions val task = async(CommonPool) { ...
 throw

    MyException()
 }
 try {
 task.await()
 } catch (e: MyException) {
 ...
 } 1 3 throw e catch (e) 2
  16. val job = async(CommonPool) {
 while (isActive) {
 ...
 }


    }
 job.cancel() Check cancellation explicitly in computation code
  17. Library suspend functions like await, delay check for cancellation val

    job = async(CommonPool) {
 delay(1000)
 task.await()
 }
 job.cancel()
  18. You can run the code without cancellation val job =

    launch(CommonPool) { try { ... } finally { run(NonCancellable) { // this code isn't cancelled } } } job.cancel()
  19. suspend fun login(login: String): UserID
 
 suspend fun loadUserData(userID: UserID):

    UserData
 
 suspend fun loadImage(id: String): Image Functions that can be suspended
  20. suspend fun showUserInfo(name: String) {
 val userID = login(name)
 val

    data = loadUserData(userID)
 val image = async(CommonPool) {
 loadImage(userData.imageID)
 }
 launch(UI) {
 showData(data)
 showImage(image.await())
 }
 } Using suspend functions
  21. Q: Where can I call suspend functions? A: Inside other

    suspend functions and inside async/launch (in fact: inside suspend lambdas).
  22. fun launch( context: CoroutineContext, block: suspend CoroutineScope.() -> Unit ):

    Job fun <T> async( context: CoroutineContext, block: suspend CoroutineScope.() -> T ) : Deferred<T> suspend lambdas
  23. suspend fun foo(): Int fun fooAsync(): CompletableFuture<Int> = future {

    foo() } fun fooAsync(): Single<Int> = rxSingle(CommonPool) { foo() } To call suspend foo from Java wrap it into fooAsync if you have Java 8 if you have RxJava
  24. fun load(s: String) = run { println("loading $s"); s }

    val seq = buildSequence { yield(load("first")) yield(load("second")) } for (s in seq) { println("processing $s") } loading first processing first loading second processing second yield when required