circa 2011 - Apache 2 licence • Initially targeted the JVM with emphasis on Java interoperability • Currently also targets javascript and native • Excellent integration with the JVM tooling ecosystem • IntelliJ IDE • Gradle and Maven build systems • E.g. Kotlin and Java source code side-by-side in the same module • Official language for Android development, since 2017 • Supported by Spring Boot 2.0, since 2017
Responsivess in UI frameworks with thread affinity (or a single thread) • Avoid blocking any thread • Scalability in “intermediate” servers • E.g. API gateways/frontends • A thread uses significant resources (e.g. 1Mb on the JVM) • Made possible by asynchronous/non-blocking IO • and asynchronous synchronization • A wait should not require a thread to be blocked • Mandatory in some environments • E.g. Android’s activities, javascript • Optional on others • E.g. Spring
programming • We may have an asynchronous flow without any parallelism • Will not make things necessarely faster • Asynchronous I/O will be slower than synchronous I/O • Better • Resource (thread) usage • Responsiveness • Better scalability
or more callbacks • E.g. Java’s NIO, NodeJS • May lead to the so called “callback hell” • Futures and Reactive Streams • Objects representing asynchronous operations • With composition methods (e.g. then, map/flatMap, ...) • E.g. CompletableFuture and Flow.Publisher • Fit nicely into a functional programming style • Functions created by the composition of other functions
• Functions created by sequences of statements • On async functions, an await converts a Future<V> into a V, without blocking • Increasing popularity • Available in C#, Javascript, Python, Dart, ... • Instead of async-await, Kotlin uses a different (yet related) concept Coroutines
C# - Task<T> type • JS – Promises+ specification • In the JVM world the scenario is quite the opposite • Guava – ListenableFuture • Spring – DeferredResult • JDK 8 – CompletableFuture • Apache HTTP Client – callbacks • A library based approach work best in this heterogenous scenario • E.g. Multiple await extension functions, one for each future type.
continuation.resume(Unit) }, ms, TimeUnit.MILLISECONDS) } } suspend fun suspendFunctionNonBlockingWait2(a: Int, b: Int): Int { log.info("step 1") delay(1000) log.info("step 2") return a + b } same scope Run on different threads
{ for(i in 0..3) { log.info("step 1 of iteration $i") if(i % 2 == 0) { delay(1000) } log.info("step 2 of iteration $i") } return a + b } 14:51:25.344 [main] INFO intro - step 1 of iteration 0 14:51:26.349 [pool-1-thread-1] INFO intro - step 2 of iteration 0 14:51:26.349 [pool-1-thread-1] INFO intro - step 1 of iteration 1 14:51:26.349 [pool-1-thread-1] INFO intro - step 2 of iteration 1 14:51:26.349 [pool-1-thread-1] INFO intro - step 1 of iteration 2 14:51:27.349 [pool-1-thread-3] INFO intro - step 2 of iteration 2 14:51:27.350 [pool-1-thread-3] INFO intro - step 1 of iteration 3 14:51:27.350 [pool-1-thread-3] INFO intro - step 2 of iteration 3 14:51:27.350 [pool-1-thread-3] INFO intro - result is 42
suspendCoroutine<T> { continuation -> this.whenComplete({value, error -> if (error != null) continuation.resumeWithException(error) else continuation.resume(value) })} await is an extension function on CompletableFuture Converts a CompletableFuture<T> into a T • without blocking • Similar to the await operator from C#/JS, however defined as a function
suspend suspend suspend suspend regular function • suspend functions can only be called from other suspend functions • E.g. main cannot be a suspend function • E.g. a suspend method cannot override a non-suspend method • E.g. a suspend method cannot be a Spring MVC controller handler
() -> T).startCoroutine(completion: Continuation<T>) • Is an extension method • For suspend functions that return a T • Receives a Continuation<T>, i.e., a callback based interface • It is not a suspend method so can be called from any function • suspendCoroutine converts callback/futures into suspend functions • startCoroutine converts back from suspend functions into callbacks/futures Callback/future suspendCoroutine suspend suspend startCoroutine suspend regular function using callbacks
{ getTagsForReposInOrgs("https://api.github.com/users/ktorio/repos") } • Plain old Spring controller handler (DeferredResult is a Spring type) • getTagsForReposInOrgs is a suspend function • deferred converts from suspend into DeferredResult using startCoroutine fun <T> deferred(block: suspend () -> T): DeferredResult<T> { val result = DeferredResult<T>() block.startCoroutine(object : Continuation<T> { override fun resume(value: T) { result.setResult(value) } override fun resumeWithException(exception: Throwable) { result.setErrorResult(exception) } (...) } return result }
machine • With a different signature – continuation passing style • A suspend fun someFunction(a: Int, b: Int): Int • Is converted into Object someFunction(a: Int, b: Int, Continuation<Int> continuation) • An internal call to a suspend fuction automatically uses the next state as the continuation • The next state is made available via the suspendCoroutine lambda • That’s why a normal function cannot call a suspend function directly • The continuation needs to be passed in • Which is what startCoroutine does • A coroutine is an instance of the state machine defined by a suspend function
run? • It depends on the active CoroutineDispatcher • Unconfined • First segment runs on thread that called startCoroutine... • ...and then on the threads where the continuation methods where called • I.e. No thread switching is done by the Kotlin runtime • CommonPool • Coroutine runs on threads from the Java ForkJoinPool • UI • Coroutine runs on Android’s UI thread • Others • Dispatcher is defined when calling the coroutine builder – • E.g. launch(UI) {...}
= await loadImage(...) doSomething(img1, img2) val img1 = loadImage(...) val img2 = loadImage(...) doSomething(img1, img2) Kotlin C#/JS Sequential (yet asynchronous) Based on example present in https://qconsf.com/sf2017/system/files/presentation-slides/2017_qcon_sf_-_fresh_async_with_kotlin.pdf by Roman Elizarov
= await loadImage(...) doSomething(img1, img2) val img1 = loadImage(...) val img2 = loadImage(...) doSomething(img1, img2) var f1 = loadImage(...) var f2 = loadImage(...) doSomething(await f1, await f2) val f1 = async { loadImage(...) } val f2 = async { loadImage(...) } doSomething(f1.await(), f2.await()) Kotlin C#/JS Sequential (yet asynchronous) Parallel Based on example present in https://qconsf.com/sf2017/system/files/presentation-slides/2017_qcon_sf_-_fresh_async_with_kotlin.pdf by Roman Elizarov
T to Task<T> Return type is still T async is a private implementation detail suspend is visible on the signature async function can be called by any function suspend function can only be called by another suspend function (or startCoroutine) Consumer can use the Task<T> directly or obtain the T via an await Consumer only sees the T (no await required) Parallel by default Sequential by default Sequential needs explicit await Parallel needs explicit async await is a language operator - C#: operand must have an GetAwaiter method - JS: operand must be Promise/thenable await are library provided functions - Can be added, as an extension function, to any future-like type Task<T> is C#. In JS it would be a Promise/thenable
• Coroutine context • Cancellation and timeouts • Resources • The two KotlinConf 2017 sessions on coroutines by Roman Elizarov • https://github.com/Kotlin/kotlinx.coroutines/blob/master/coroutines-guide.md • Coroutines in action • https://ktor.io – framework for building asynchronous servers and clients