mersan
11/26/2018, 10:47 PMoleksiyp
11/26/2018, 11:15 PMCoroutine in Kotlin
* allows suspension in the middle of execution
* small resources are occupied during suspension(threads are free)
* suspension achieved by code transformation at compile time
* shortly, it solves the problem of callback hell in asynchronous programs
Kotlin
* as a language, provides only minimal low-level APIs
* e.g. `async` and `await` are not keywords in Kotlin, not even in the standard library
* concept of suspending function provides a safer abstraction for asynchronous operations than futures and promises.
* on another hand `kotlinx.coroutines` is a rich library with many primitives
Simplest example
import kotlinx.coroutines.*
fun main() {
GlobalScope.launch { // launch new coroutine
delay(1000L) // do not block any thread
// and schedules continunation to be executed
// after 1 second
println("World!") // continuation
}
println("Hello,")
Thread.sleep(2000L) // block main thread for 2 seconds
}
here GlobalScope allows launching coroutines as a daemon
Blocking world bridge
import kotlinx.coroutines.*
fun main() = runBlocking {
repeat(100_000) { // launch a lot of coroutines, not a problem
launch {
delay(1000L)
print(".")
}
}
}
here launch is performed in the scope of runBlocking, not global scope
runBlocking waits for all launched coroutines to finish
runBlocking blocks the thread that was executed on
Cancellation
val job = launch {
try {
repeat(1000) { i ->
println("I'm sleeping $i ...")
delay(500L)
}
} finally {
println("I'm running finally")
}
}
delay(1300L) // delay a bit
println("main: I'm tired of waiting!")
job.cancelAndJoin() // cancels the job and waits for its completion
println("main: Now I can quit.")
I'm sleeping 0 ...
I'm sleeping 1 ...
I'm sleeping 2 ...
main: I'm tired of waiting!
I'm running finally
main: Now I can quit.
import kotlinx.coroutines.*
import kotlin.system.*
Async / await
fun main() = runBlocking {
val one = async { doSomethingUsefulOne() }
val two = async { doSomethingUsefulTwo() }
println("The answer is ${one.await() + two.await()}")
}
suspend fun doSomethingUsefulOne(): Int {
delay(1000L) // pretend we are doing something useful here
return 13
}
suspend fun doSomethingUsefulTwo(): Int {
delay(1000L) // pretend we are doing something useful here, too
return 29
}
Adapting any asynchronous library to coroutines
fun sync() {
val client = OkHttpClient();
val request = Request.Builder()
.url("<https://www.ubs.com>")
.build();
val call: Call = client.newCall(request)
val execute: Response = call.execute()
println(execute.message())
}
Adapting any asynchronous library to coroutines
fun async() {
val client = OkHttpClient();
val request = Request.Builder()
.url("<https://www.ubs.com>")
.build();
val call: Call = client.newCall(request)
call.enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
println("Error: " + e.message)
}
override fun onResponse(call: Call, response: Response) {
println(response.message())
}
});
}
Adapting any asynchronous library to coroutines
suspend fun suspended() {
val client = OkHttpClient();
val request = Request.Builder()
.url("<https://www.ubs.com>")
.build();
val call: Call = client.newCall(request)
val response: Response = enqueueAndWait(call)
println(response.message())
}
suspend fun enqueueAndWait(call: Call): Response = suspendCoroutine { continuation ->
call.enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
continuation.resumeWithException(e)
}
override fun onResponse(call: Call, response: Response) {
continuation.resume(response)
}
})
}
Adaptor libraries in kotlinx.coroutine
kotlinx-coroutines-reactive -- utilities for Reactive Streams
kotlinx-coroutines-reactor -- utilities for Reactor
kotlinx-coroutines-rx2 -- utilities for RxJava 2.x
kotlinx-coroutines-jdk8 -- integration with JDK8 CompletableFuture (Android API level 24).
kotlinx-coroutines-guava -- integration with Guava ListenableFuture.
kotlinx-coroutines-slf4j -- integration with SLF4J MDC.
kotlinx-coroutines-play-services -- integration with Google Play Services Tasks API.
kotlinx-coroutines-android -- Dispatchers.Main context for Android applications.
kotlinx-coroutines-javafx -- Dispatchers.JavaFx context for JavaFX UI applications.
kotlinx-coroutines-swing -- Dispatchers.Swing context for Swing UI applications.
Any asynchronous library may be adapted like we've seen with OkHttp quite easily
Example of reactor mono / flux
val mono: Mono<Int> = mono {
delay(500)
5
}
val flux: Flux<Int> = flux {
for (i in 1..10) {
send(i)
delay(500)
}
}
mersan
11/27/2018, 9:43 AM