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

Kotlin Coroutines

Svetlana Isakova
May 09, 2017
760

Kotlin Coroutines

Introduction to coroutines in Kotlin
presented at MCE

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