This document discusses asynchronous programming in Kotlin using various abstractions like callbacks, futures, observables, and coroutines. It presents an example of making multiple asynchronous requests sequentially and shows how different abstractions can execute them in parallel to improve performance. Coroutines are highlighted as providing a synchronous style of programming while allowing asynchronous execution through suspending functions. The conclusions recommend choosing the best abstraction based on the specific use case and considering both simplicity and efficiency.
4. 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.
6. 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
7. 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.
8. 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.
10. 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.
11. MAD · NOV 23-24 · 2018
Promises
CompletableFuture
Futures
Deferred
Task Asynctask
Observable
Callbacks
Async abstractions!!!!
Coroutines/Suspending function
12. 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.
16. 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
17. MAD · NOV 23-24 · 2018
CompetableFutures
And well, the others ‘Futures’
18. 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
19. 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.
■ ...
20. 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().
21. MAD · NOV 23-24 · 2018
CompletableFutures - Our use case
■ getUserInfo(): CompletableFuture<...>.
■ getPhotos(): CompletableFuture<...>.
■ getFriends(): CompletableFuture<...>.
■ getNews(): CompletableFuture<...>.
22. 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
23. 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
24. 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
25. 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 …
26. MAD · NOV 23-24 · 2018
CompletableFutures - Exceptions & Timeouts
Final line reached
Time required: 26
Request: Session ...
Empty page
27. 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.
29. MAD · NOV 23-24 · 2018
Observable
“Everything is a stream, and it's observable.”
kotlinlang.org/docs/tutorials/coroutines/async-programming.html
30. 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
31. 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
35. MAD · NOV 23-24 · 2018
Observable - Blocking
Request: Session …
println ...
Time required: 771
36. MAD · NOV 23-24 · 2018
Observable - Our use case
233 ms
1654 ms
37. MAD · NOV 23-24 · 2018
Reactive Streams
A lot of useful diagrams to understand operators:
■ Marbles diagrams - rxmarbles.com
38. 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…).
40. 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
41. 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.
42. MAD · NOV 23-24 · 2018
Default context (Thread Pool)
in Kotlin
Scope
Coroutine
Coroutine
Coroutine
IO context
Scope
Coroutine
Main
Thread
Scope
Coroutine
43. MAD · NOV 23-24 · 2018
Coroutines - Creation in IO
IO context
Scope
Coroutine
Scope
Coroutine
44. MAD · NOV 23-24 · 2018
Coroutines in Kotlin
Request: Session ...
Request: UserInfo ...
Request: Friends …
Request: Photos …
Request: News ...
Page for …
Time required: 2676
45. MAD · NOV 23-24 · 2018
Coroutines in Kotlin
Request: Session ...
Request: UserInfo ...
Request: Friends …
Request: Photos …
Request: News ...
Page for …
Time required: 1653
46. 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.
47. 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.
48. 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.
49. 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