KEMBAR78
CommitConf 2018 - Going Async With Kotlin | PDF
MAD · NOV 23-24 · 2018
Going Async with Kotlin
José María Muñoz Rey
Software Engineer at Tuenti
MAD · NOV 23-24 · 2018
MAD · NOV 23-24 · 2018
Where should we start?
Simplified problem: multiple IO request
Index
■ Understand why asynchrony abstractions
matters.
■ Asynchrony abstractions.
∘ Callbacks.
∘ Futures (CompletableFutures).
∘ Observables (Reactive Streams/RxJava).
∘ Coroutines.
MAD · NOV 23-24 · 2018
Writing synchronous
code
Why asynchrony abstraction matters
MAD · NOV 23-24 · 2018
Problem description
Simple IO problem: multiple requests to a service.
Client:
■ Standard Kotlin, sequential code.
■ Without async abstractions.
Server:
■ Ktor.
■ Just responds with a text and waits a custom delay.
MAD · NOV 23-24 · 2018
Our example
MAD · NOV 23-24 · 2018
Simple Synchronous code
Request: Session, 500 miliseconds
...
Request: Photos, 500 miliseconds
Request: News, 500 miliseconds
Time required to process this block: 2626
Requests
Response
MAD · NOV 23-24 · 2018
Simple Synchronous code
What happened? Requests
still made sequentially:
■ Main thread blocked: in
each request.
■ No parallelism: this code
can be benefit from it.
MAD · NOV 23-24 · 2018
What do we need?
■ Last 3 request should run in parallel
■ Abstractions to:
∘ Create them.
∘ Get status, cancel…
∘ Get computed value.
We need to call
these methods
asynchronously.
MAD · NOV 23-24 · 2018
Managing Asynchrony
MAD · NOV 23-24 · 2018
Let’s create Threads for IO !!
They help us by letting other code run in parallel, but:
■ They have an high costs (Context switching).
■ They are highly limited.
■ They are hard to manage.
∘ Create/reuse/idle/close.
∘ Cancel work.
∘ Thread pool (computation, IO).
∘ Share info.
We need some
abstractions.
MAD · NOV 23-24 · 2018
Promises
CompletableFuture
Futures
Deferred
Task Asynctask
Observable
Callbacks
Async abstractions!!!!
Coroutines/Suspending function
MAD · NOV 23-24 · 2018
What we are going to see today:
Main abstractions used in the JVM
■ Callbacks.
■ Futures: CompletableFutures.
■ Observables: Reactive streams
(Publisher/subscriber/Observable...).
■ Coroutines.
MAD · NOV 23-24 · 2018
Callbacks
MAD · NOV 23-24 · 2018
Callbacks
MAD · NOV 23-24 · 2018
Callbacks
MAD · NOV 23-24 · 2018
Callbacks
■ Just if necessary.
■ Not enough for Kotlin to handle asynchrony
■ Problems to chain calls (Callbacks hell).
■ Problems to share computed values.
■ Problems to handle errors.
Javascript experience: people is moving away.
DON’T USE THEM
MAD · NOV 23-24 · 2018
CompetableFutures
And well, the others ‘Futures’
MAD · NOV 23-24 · 2018
Promises vs Futures vs CompletableFuture vs
Deferred vs Task vs ...
“They describe an object that acts as a proxy for a result
that is initially unknown, usually because the computation
of its value is yet incomplete.”
en.wikipedia.org/wiki/Futures_and_promises
MAD · NOV 23-24 · 2018
Promises vs Futures vs CompletableFuture vs
Deferred vs Task vs ...
They are (practically) the same thing, but named differently
in different languages:
■ Futures: practically everywhere.
■ CompletableFutures: JVM (Java, Kotlin...).
■ Promises: Javascript.
■ Task: C# / Android APIs.
■ Deferred: Koltin.
■ ...
MAD · NOV 23-24 · 2018
CompletableFutures
■ Introduced in Java 8.
■ Improves the actual interface of existing Futures.
■ Compositional programming with chained calls. (Sequential and parallel).
■ Default: Threads from the CommonPool.
API:
■ Create: .supplyAsync()
■ Chain: .thenCompose(), .thenApply() or .thenAccept().
■ Compose: .anyOf(...), .allOf(...).
■ Get value: .get() or .join().
■ More functionality: .exceptionally(...), .orTimeout().
MAD · NOV 23-24 · 2018
CompletableFutures - Our use case
■ getUserInfo(): CompletableFuture<...>.
■ getPhotos(): CompletableFuture<...>.
■ getFriends(): CompletableFuture<...>.
■ getNews(): CompletableFuture<...>.
MAD · NOV 23-24 · 2018
CompletableFutures - Our use case: Version 1
Request: Session, ...
Request: UserInfo, ...
Request: Friends, ...
Request: Photos, ...
Request: News,...
Page for ...
Time required ...2626
Final line reached
MAD · NOV 23-24 · 2018
CompletableFutures - Our use case: Version 2
Request: Session, ...
Request: UserInfo, ...
Request: Friends, ...
Request: Photos, ...
Request: News, ...
Page for ...
Time required: 1632
Final line reached
MAD · NOV 23-24 · 2018
CompletableFutures - Our use case: Version 3
Final line reached
Request: Session ...
Request: UserInfo ...
Request: Friends ...
Request: Photos ...
Request: News, ...
Page for ...
Time required: 1640
MAD · NOV 23-24 · 2018
CompletableFutures - Our use case: Version 4
Final line reached
Time required: 17
Request: Session …
Request: UserInfo …
Request: Photos …
Request: Friends …
Request: News …
Page for …
MAD · NOV 23-24 · 2018
CompletableFutures - Exceptions & Timeouts
Final line reached
Time required: 26
Request: Session ...
Empty page
MAD · NOV 23-24 · 2018
CompletableFutures - Conclusions
Good things:
■ A lot of facilidades to manage async operations.
■ Code looks ‘synchronous’.
■ Easy to compose complex async operations.
But:
■ Still some sense of callbacks.
■ Still blocks the caller thread in some point.
■ Remember to manage your Thread Pools.
MAD · NOV 23-24 · 2018
Reactive Streams
MAD · NOV 23-24 · 2018
Observable
“Everything is a stream, and it's observable.”
kotlinlang.org/docs/tutorials/coroutines/async-programming.html
MAD · NOV 23-24 · 2018
Observables
■ Publishers notifies subscriptions about new data.
RxJava
■ Implements the Observable pattern and extends it.
■ Creation of flows looks like a Builder.
■ Operators.
■ Backpresure.
■ Schedulers (Default, IO, Compute).
■ RxJava & RxKotlin (and other ~16 languages).
Read lines
Split by spaces
Remove some
words
Print
MAD · NOV 23-24 · 2018
Observables
1º Publisher
■ Observable<...> / Flowable<...>
∘ Others: Single<...>, Maybe<...>, Completable<...>...
2º Operators
■ Optionals, between 72 and ~500.
■ Transformations: flatMap(), map() ...
■ Mathematical: count(), max(), min()...
■ Filtering: first(), find(), filter()...
3º Subscription
■ Run the flow.
■ Will run the steps in different schedulers: subscribeOn(...)
observeOn(...)... Default: Local Thread.
■ Obtain the final value: subscription(...), blockingFirst(...)...
Read lines
Split by spaces
Remove some
words
Print
MAD · NOV 23-24 · 2018
Observable - Create
MAD · NOV 23-24 · 2018
Observable - Just a try
Request: Session ...
println ...
Request: Session ...
println ...
Request: Session ...
println ...
Time required: 1743
MAD · NOV 23-24 · 2018
Observable - Scheduler IO
Time required: 190
Request: Session ...
Request: Session ...
Request: Session ...
println …
println …
println …
MAD · NOV 23-24 · 2018
Observable - Blocking
Request: Session …
println ...
Time required: 771
MAD · NOV 23-24 · 2018
Observable - Our use case
233 ms
1654 ms
MAD · NOV 23-24 · 2018
Reactive Streams
A lot of useful diagrams to understand operators:
■ Marbles diagrams - rxmarbles.com
MAD · NOV 23-24 · 2018
Reactive Streams / RxJava - Conclusions
Good things:
■ A lot of facilidades to manage async flows.
■ Managed schedulers.
■ A lot of operators.
But:
■ Too complex for individual tasks.
■ Has a very big API.
■ Easy to make mistakes (sync, operators…).
MAD · NOV 23-24 · 2018
Coroutines
MAD · NOV 23-24 · 2018
Coroutines
“The idea that a function can suspend its execution at
some point and resume later on.”
kotlinlang.org/docs/tutorials/coroutines/async-programming.html
MAD · NOV 23-24 · 2018
Suspending functions - Coroutines
Suspending Functions (our code):
■ Async code written Synchronous, that can run asynchronously. Sync
by default.
■ Async/await in Javacript, C#, Python.
Coroutines (runners):
■ ‘Light-weight’ Threads BUT Coroutines != Threads.
∘ Coroutines run in threads (1.000.000s).
∘ A SUSPENDED coroutine:
· Does not consume a thread.
· Is not bound to a thread.
MAD · NOV 23-24 · 2018
Default context (Thread Pool)
in Kotlin
Scope
Coroutine
Coroutine
Coroutine
IO context
Scope
Coroutine
Main
Thread
Scope
Coroutine
MAD · NOV 23-24 · 2018
Coroutines - Creation in IO
IO context
Scope
Coroutine
Scope
Coroutine
MAD · NOV 23-24 · 2018
Coroutines in Kotlin
Request: Session ...
Request: UserInfo ...
Request: Friends …
Request: Photos …
Request: News ...
Page for …
Time required: 2676
MAD · NOV 23-24 · 2018
Coroutines in Kotlin
Request: Session ...
Request: UserInfo ...
Request: Friends …
Request: Photos …
Request: News ...
Page for …
Time required: 1653
MAD · NOV 23-24 · 2018
Coroutines in Kotlin
Kotlin release:
■ API stable in Kotlin 1.3
■ Implementation version (kotlinx-coroutines-core): 1.0.1
More functionality:
■ Parent-child & Jobs -> cancellables.
■ Try/Catch & Stacktraces.
■ Channels (fan-in, fan-out, pipelines…).
■ Actors.
■ Multi-platform: JS, Native, Reactive, Android.
MAD · NOV 23-24 · 2018
Coroutines - Conclusions
Good things:
■ Strong primitives to build async software.
■ Sometimes it feels just synchronous (Try catch).
■ For our use case ~efficiency than CompletableFuture.
But:
■ Scopes and contexts are a little bit messy.
■ Partial ‘non-blocking’. You still need to take care of Threads.
■ Could be too low level.
MAD · NOV 23-24 · 2018
General - Conclusions
■ Concurrency/parallelism is hard.
■ UnitTest and measure (!) your implementations.
■ Coroutines improved readability and efficiency, but:
∘ Final version just released.
∘ Community support just started.
∘ Take care of threads.
∘ Use the conversions with other abstractions.
■ Look for the better abstraction for your use case.
∘ CompletableFuture: Simple and efficient over single jobs.
∘ Coroutines: Abstractions over single jobs and other primitives.
∘ Reactive Streams: Abstractions over an stream of jobs.
MAD · NOV 23-24 · 2018
Resources
■ Slides & Code: @Koletzilla
■ Kotlin proposal (KEEP)
∘ https://github.com/Kotlin/KEEP/blob/master/proposals/coroutines.md
■ Kotlin/kotlinx.coroutines
∘ https://github.com/Kotlin/kotlinx.coroutines
■ Introduction to Coroutines @ KotlinConf 2017 - by Roman Elizarov
∘ https://www.youtube.com/watch?v=_hfBv0a09Jc
∘ https://www.slideshare.net/elizarov/introduction-to-coroutines-kotlinconf-2017
■ Kotlin Coroutines in Practice @ KotlinConf 2018 - by Roman Elizarov
∘ https://www.youtube.com/watch?v=a3agLJQ6vt8
∘ https://www.slideshare.net/elizarov/kotlin-coroutines-in-practice-kotlinconf-2018
MAD · NOV 23-24 · 2018
Thank you!!
Questions?
@Koletzilla
CommitConf 2018 - Going Async With Kotlin

CommitConf 2018 - Going Async With Kotlin

  • 1.
    MAD · NOV23-24 · 2018 Going Async with Kotlin José María Muñoz Rey Software Engineer at Tuenti MAD · NOV 23-24 · 2018
  • 2.
    MAD · NOV23-24 · 2018 Where should we start? Simplified problem: multiple IO request Index ■ Understand why asynchrony abstractions matters. ■ Asynchrony abstractions. ∘ Callbacks. ∘ Futures (CompletableFutures). ∘ Observables (Reactive Streams/RxJava). ∘ Coroutines.
  • 3.
    MAD · NOV23-24 · 2018 Writing synchronous code Why asynchrony abstraction matters
  • 4.
    MAD · NOV23-24 · 2018 Problem description Simple IO problem: multiple requests to a service. Client: ■ Standard Kotlin, sequential code. ■ Without async abstractions. Server: ■ Ktor. ■ Just responds with a text and waits a custom delay.
  • 5.
    MAD · NOV23-24 · 2018 Our example
  • 6.
    MAD · NOV23-24 · 2018 Simple Synchronous code Request: Session, 500 miliseconds ... Request: Photos, 500 miliseconds Request: News, 500 miliseconds Time required to process this block: 2626 Requests Response
  • 7.
    MAD · NOV23-24 · 2018 Simple Synchronous code What happened? Requests still made sequentially: ■ Main thread blocked: in each request. ■ No parallelism: this code can be benefit from it.
  • 8.
    MAD · NOV23-24 · 2018 What do we need? ■ Last 3 request should run in parallel ■ Abstractions to: ∘ Create them. ∘ Get status, cancel… ∘ Get computed value. We need to call these methods asynchronously.
  • 9.
    MAD · NOV23-24 · 2018 Managing Asynchrony
  • 10.
    MAD · NOV23-24 · 2018 Let’s create Threads for IO !! They help us by letting other code run in parallel, but: ■ They have an high costs (Context switching). ■ They are highly limited. ■ They are hard to manage. ∘ Create/reuse/idle/close. ∘ Cancel work. ∘ Thread pool (computation, IO). ∘ Share info. We need some abstractions.
  • 11.
    MAD · NOV23-24 · 2018 Promises CompletableFuture Futures Deferred Task Asynctask Observable Callbacks Async abstractions!!!! Coroutines/Suspending function
  • 12.
    MAD · NOV23-24 · 2018 What we are going to see today: Main abstractions used in the JVM ■ Callbacks. ■ Futures: CompletableFutures. ■ Observables: Reactive streams (Publisher/subscriber/Observable...). ■ Coroutines.
  • 13.
    MAD · NOV23-24 · 2018 Callbacks
  • 14.
    MAD · NOV23-24 · 2018 Callbacks
  • 15.
    MAD · NOV23-24 · 2018 Callbacks
  • 16.
    MAD · NOV23-24 · 2018 Callbacks ■ Just if necessary. ■ Not enough for Kotlin to handle asynchrony ■ Problems to chain calls (Callbacks hell). ■ Problems to share computed values. ■ Problems to handle errors. Javascript experience: people is moving away. DON’T USE THEM
  • 17.
    MAD · NOV23-24 · 2018 CompetableFutures And well, the others ‘Futures’
  • 18.
    MAD · NOV23-24 · 2018 Promises vs Futures vs CompletableFuture vs Deferred vs Task vs ... “They describe an object that acts as a proxy for a result that is initially unknown, usually because the computation of its value is yet incomplete.” en.wikipedia.org/wiki/Futures_and_promises
  • 19.
    MAD · NOV23-24 · 2018 Promises vs Futures vs CompletableFuture vs Deferred vs Task vs ... They are (practically) the same thing, but named differently in different languages: ■ Futures: practically everywhere. ■ CompletableFutures: JVM (Java, Kotlin...). ■ Promises: Javascript. ■ Task: C# / Android APIs. ■ Deferred: Koltin. ■ ...
  • 20.
    MAD · NOV23-24 · 2018 CompletableFutures ■ Introduced in Java 8. ■ Improves the actual interface of existing Futures. ■ Compositional programming with chained calls. (Sequential and parallel). ■ Default: Threads from the CommonPool. API: ■ Create: .supplyAsync() ■ Chain: .thenCompose(), .thenApply() or .thenAccept(). ■ Compose: .anyOf(...), .allOf(...). ■ Get value: .get() or .join(). ■ More functionality: .exceptionally(...), .orTimeout().
  • 21.
    MAD · NOV23-24 · 2018 CompletableFutures - Our use case ■ getUserInfo(): CompletableFuture<...>. ■ getPhotos(): CompletableFuture<...>. ■ getFriends(): CompletableFuture<...>. ■ getNews(): CompletableFuture<...>.
  • 22.
    MAD · NOV23-24 · 2018 CompletableFutures - Our use case: Version 1 Request: Session, ... Request: UserInfo, ... Request: Friends, ... Request: Photos, ... Request: News,... Page for ... Time required ...2626 Final line reached
  • 23.
    MAD · NOV23-24 · 2018 CompletableFutures - Our use case: Version 2 Request: Session, ... Request: UserInfo, ... Request: Friends, ... Request: Photos, ... Request: News, ... Page for ... Time required: 1632 Final line reached
  • 24.
    MAD · NOV23-24 · 2018 CompletableFutures - Our use case: Version 3 Final line reached Request: Session ... Request: UserInfo ... Request: Friends ... Request: Photos ... Request: News, ... Page for ... Time required: 1640
  • 25.
    MAD · NOV23-24 · 2018 CompletableFutures - Our use case: Version 4 Final line reached Time required: 17 Request: Session … Request: UserInfo … Request: Photos … Request: Friends … Request: News … Page for …
  • 26.
    MAD · NOV23-24 · 2018 CompletableFutures - Exceptions & Timeouts Final line reached Time required: 26 Request: Session ... Empty page
  • 27.
    MAD · NOV23-24 · 2018 CompletableFutures - Conclusions Good things: ■ A lot of facilidades to manage async operations. ■ Code looks ‘synchronous’. ■ Easy to compose complex async operations. But: ■ Still some sense of callbacks. ■ Still blocks the caller thread in some point. ■ Remember to manage your Thread Pools.
  • 28.
    MAD · NOV23-24 · 2018 Reactive Streams
  • 29.
    MAD · NOV23-24 · 2018 Observable “Everything is a stream, and it's observable.” kotlinlang.org/docs/tutorials/coroutines/async-programming.html
  • 30.
    MAD · NOV23-24 · 2018 Observables ■ Publishers notifies subscriptions about new data. RxJava ■ Implements the Observable pattern and extends it. ■ Creation of flows looks like a Builder. ■ Operators. ■ Backpresure. ■ Schedulers (Default, IO, Compute). ■ RxJava & RxKotlin (and other ~16 languages). Read lines Split by spaces Remove some words Print
  • 31.
    MAD · NOV23-24 · 2018 Observables 1º Publisher ■ Observable<...> / Flowable<...> ∘ Others: Single<...>, Maybe<...>, Completable<...>... 2º Operators ■ Optionals, between 72 and ~500. ■ Transformations: flatMap(), map() ... ■ Mathematical: count(), max(), min()... ■ Filtering: first(), find(), filter()... 3º Subscription ■ Run the flow. ■ Will run the steps in different schedulers: subscribeOn(...) observeOn(...)... Default: Local Thread. ■ Obtain the final value: subscription(...), blockingFirst(...)... Read lines Split by spaces Remove some words Print
  • 32.
    MAD · NOV23-24 · 2018 Observable - Create
  • 33.
    MAD · NOV23-24 · 2018 Observable - Just a try Request: Session ... println ... Request: Session ... println ... Request: Session ... println ... Time required: 1743
  • 34.
    MAD · NOV23-24 · 2018 Observable - Scheduler IO Time required: 190 Request: Session ... Request: Session ... Request: Session ... println … println … println …
  • 35.
    MAD · NOV23-24 · 2018 Observable - Blocking Request: Session … println ... Time required: 771
  • 36.
    MAD · NOV23-24 · 2018 Observable - Our use case 233 ms 1654 ms
  • 37.
    MAD · NOV23-24 · 2018 Reactive Streams A lot of useful diagrams to understand operators: ■ Marbles diagrams - rxmarbles.com
  • 38.
    MAD · NOV23-24 · 2018 Reactive Streams / RxJava - Conclusions Good things: ■ A lot of facilidades to manage async flows. ■ Managed schedulers. ■ A lot of operators. But: ■ Too complex for individual tasks. ■ Has a very big API. ■ Easy to make mistakes (sync, operators…).
  • 39.
    MAD · NOV23-24 · 2018 Coroutines
  • 40.
    MAD · NOV23-24 · 2018 Coroutines “The idea that a function can suspend its execution at some point and resume later on.” kotlinlang.org/docs/tutorials/coroutines/async-programming.html
  • 41.
    MAD · NOV23-24 · 2018 Suspending functions - Coroutines Suspending Functions (our code): ■ Async code written Synchronous, that can run asynchronously. Sync by default. ■ Async/await in Javacript, C#, Python. Coroutines (runners): ■ ‘Light-weight’ Threads BUT Coroutines != Threads. ∘ Coroutines run in threads (1.000.000s). ∘ A SUSPENDED coroutine: · Does not consume a thread. · Is not bound to a thread.
  • 42.
    MAD · NOV23-24 · 2018 Default context (Thread Pool) in Kotlin Scope Coroutine Coroutine Coroutine IO context Scope Coroutine Main Thread Scope Coroutine
  • 43.
    MAD · NOV23-24 · 2018 Coroutines - Creation in IO IO context Scope Coroutine Scope Coroutine
  • 44.
    MAD · NOV23-24 · 2018 Coroutines in Kotlin Request: Session ... Request: UserInfo ... Request: Friends … Request: Photos … Request: News ... Page for … Time required: 2676
  • 45.
    MAD · NOV23-24 · 2018 Coroutines in Kotlin Request: Session ... Request: UserInfo ... Request: Friends … Request: Photos … Request: News ... Page for … Time required: 1653
  • 46.
    MAD · NOV23-24 · 2018 Coroutines in Kotlin Kotlin release: ■ API stable in Kotlin 1.3 ■ Implementation version (kotlinx-coroutines-core): 1.0.1 More functionality: ■ Parent-child & Jobs -> cancellables. ■ Try/Catch & Stacktraces. ■ Channels (fan-in, fan-out, pipelines…). ■ Actors. ■ Multi-platform: JS, Native, Reactive, Android.
  • 47.
    MAD · NOV23-24 · 2018 Coroutines - Conclusions Good things: ■ Strong primitives to build async software. ■ Sometimes it feels just synchronous (Try catch). ■ For our use case ~efficiency than CompletableFuture. But: ■ Scopes and contexts are a little bit messy. ■ Partial ‘non-blocking’. You still need to take care of Threads. ■ Could be too low level.
  • 48.
    MAD · NOV23-24 · 2018 General - Conclusions ■ Concurrency/parallelism is hard. ■ UnitTest and measure (!) your implementations. ■ Coroutines improved readability and efficiency, but: ∘ Final version just released. ∘ Community support just started. ∘ Take care of threads. ∘ Use the conversions with other abstractions. ■ Look for the better abstraction for your use case. ∘ CompletableFuture: Simple and efficient over single jobs. ∘ Coroutines: Abstractions over single jobs and other primitives. ∘ Reactive Streams: Abstractions over an stream of jobs.
  • 49.
    MAD · NOV23-24 · 2018 Resources ■ Slides & Code: @Koletzilla ■ Kotlin proposal (KEEP) ∘ https://github.com/Kotlin/KEEP/blob/master/proposals/coroutines.md ■ Kotlin/kotlinx.coroutines ∘ https://github.com/Kotlin/kotlinx.coroutines ■ Introduction to Coroutines @ KotlinConf 2017 - by Roman Elizarov ∘ https://www.youtube.com/watch?v=_hfBv0a09Jc ∘ https://www.slideshare.net/elizarov/introduction-to-coroutines-kotlinconf-2017 ■ Kotlin Coroutines in Practice @ KotlinConf 2018 - by Roman Elizarov ∘ https://www.youtube.com/watch?v=a3agLJQ6vt8 ∘ https://www.slideshare.net/elizarov/kotlin-coroutines-in-practice-kotlinconf-2018
  • 50.
    MAD · NOV23-24 · 2018 Thank you!! Questions? @Koletzilla