SlideShare a Scribd company logo
training@instil.co
January 2019
© Instil Software 2019
Demystifying Kotlin Coroutines
GDG Dublin
@BoyleEamonn
Eamonn Boyle
Me
Us
Develop
Consult
Train
We’ve really bought into Kotlin
Kotlin Conf 2018
We held a workshop at the conference
• React Web App with Kotlin on Server & Browser
Kotlin Conf 2018
Kotlin Belfast User Group
Our Kotlin Courses
Our Kotlin Courses
47 Degrees
Coroutines
Long Story Short - Synchronous is Easy
fun doWork() {
disableUI()
val exchangeRates = readExchangeRate()
val report = buildReport(exchangeRates)
saveReport(report)
enableUI()
}
1
2
3
4
5
imdb.com
return
Long Story Short - Synchronous is Easy
fun doWork() {
disableUI()
val exchangeRates = readExchangeRate()
val report = buildReport(exchangeRates)
saveReport(report)
enableUI()
}
1
2
3
4
5
We can’t escape asynchronous programming
Typically we can’t block due to limited resources
But we want ways to hide the complexity of async
Long Story Short – Callback Hell
fun doWork() {
disableUI()
readExchangeRate { exchangeRate ->
buildReport(exchangeRate) { report ->
saveReport(report) {
enableUI()
}
}
}
}
imdb.com
return
Long Story Short – Futures Help
fun doWork() {
disableUI()
readExchangeRate()
.thenCompose(::buildReport)
.thenCompose(::saveReport)
.thenApply {
enableUI()
}
}
imdb.com
Once you’ve learned the
complete API, then you have my
permission to die
return
Long Story Short – Coroutines Are Better
suspend fun doWork() {
disableUI()
val exchangeRates = readExchangeRate()
val report = buildReport(exchangeRates)
saveReport(report)
enableUI()
}
imdb.com
suspend
suspend
suspend
return
Long Story Short – Coroutines Are Better
suspend fun doWork() {
disableUI()
val exchangeRates = readExchangeRate()
val report = buildReport(exchangeRates)
saveReport(report)
enableUI()
}
fun doWork() {
disableUI()
val exchangeRates = readExchangeRate()
val report = buildReport(exchangeRates)
saveReport(report)
enableUI()
}
Long Story Short – Control Dispatch
suspend fun doWorkWithThreadControl() {
disableUI()
withContext(Dispatchers.IO) {
val exchangeRates = readExchangeRate()
val report = buildReport(exchangeRates)
saveReport(report)
}
enableUI()
}
2019-01-29 - Demystifying Kotlin Coroutines
Generator Use Case
1 2 3 4 5 6 7 1 2 3 4 5 6 7
Reading
Processing
fun readData(filename: String): List<Int> {
val data = mutableListOf<Int>()
File(filename).useLines {lines ->
lines.forEach {
val datum = it.toInt()
log("Read $datum")
data.add(datum)
}
}
return data
}
fun processData(filename: String) {
for (datum in readData(filename)) {
log("Processing data $datum")
}
}
fun readData(filename: String): List<Int> {
val data = mutableListOf<Int>()
File(filename).useLines {lines ->
lines.forEach {
val datum = it.toInt()
log("Read $datum")
data.add(datum)
}
}
return data
}
fun processData(filename: String) {
val data = readData(filename)
for (datum in data) {
log("Processing data $datum")
}
}
fun readData(filename: String): List<Int> {
val data = mutableListOf<Int>()
File(filename).useLines {lines ->
lines.forEach {
val datum = it.toInt()
log("Read $datum")
data.add(datum)
}
}
return data
}
fun processData(filename: String) {
val data = readData(filename)
for (datum in data) {
log("Processing data $datum")
}
}
fun readData(filename: String): List<Int> {
val data = mutableListOf<Int>()
File(filename).useLines {lines ->
lines.forEach {
val datum = it.toInt()
log("Read $datum")
data.add(datum)
}
}
return data
}
fun processData(filename: String) {
val data = readData(filename)
for (datum in data) {
log("Processing data $datum")
}
}
What if the read takes too
long?
What if the amount of data
read is too large?
We may need to interleave reading and processing
How should we implement this? Perhaps hand code the interleaving
• Perhaps use standard interfaces to simplify
Generator Use Case
1 2 3 4 5 6 7 1 2 3 4 5 6 7
Reading Function
Processing Function
1 1 2 2 3 3 4 4 5 5 6 6 7 7
class CustomInterleaved(filename: String) {
val file = File(filename)
.inputStream()
.bufferedReader()
fun readData(): Int {
val line = file.readLine()
if (line == null) {
file.close()
return -1
}
val datum = line.toInt()
log("Read $datum")
return datum
}
}
Manual Interleaving
fun processData(filename: String) {
val interleaved = CustomInterleaved(filename)
while (true) {
val datum = interleaved.readData()
if (datum < 0) {
break
}
log("Processing data $datum")
}
}
class CustomInterleaved(filename: String) {
val file = File(filename)
.inputStream()
.bufferedReader()
fun readData(): Int {
val line = file.readLine()
if (line == null) {
file.close()
return -1
}
val datum = line.toInt()
log("Read $datum")
return datum
}
}
Manual Interleaving
fun processData(filename: String) {
val interleaved = CustomInterleaved(filename)
while (true) {
val datum = interleaved.readData()
if (datum < 0) {
break
}
log("Processing data $datum")
}
}
class CustomIterable(val filename: String) : Iterable<Int>, AutoCloseable {
val file = File(filename).inputStream().bufferedReader()
class CustomIterator(val file: BufferedReader) : Iterator<Int> {
override fun next(): Int {
val datum = file.readLine().toInt()
log("Read $datum")
return datum
}
override fun hasNext(): Boolean = file.ready()
}
override fun iterator(): Iterator<Int> = CustomIterator(file)
override fun close() = log("Closing file")
}
Standard Idioms – Iterable Interface
class CustomIterable(val filename: String) : Iterable<Int>, AutoCloseable {
val file = File(filename).inputStream().bufferedReader()
class CustomIterator(val file: BufferedReader) : Iterator<Int> {
override fun next(): Int {
val datum = file.readLine().toInt()
log("Read $datum")
return datum
}
override fun hasNext(): Boolean = file.ready()
}
override fun iterator(): Iterator<Int> = CustomIterator(file)
override fun close() = log("Closing file")
}
Standard Idioms – Iterable Interface
fun processData(filename: String) {
CustomIterable(filename).use {data ->
for (datum in data) {
log("Processing data $datum")
}
}
}
Benefit – Simpler Usage
fun readData(filename: String): List<Int> {
val data = mutableListOf<Int>()
File(filename).useLines {lines ->
lines.forEach {
val datum = it.toInt()
log("Read $datum")
data.add(datum)
}
}
return data
}
fun processData(filename: String) {
for (datum in readData(filename)) {
log("Processing data $datum")
}
}
fun readData(filename: String): Sequence<Int> {
return sequence {
File(filename).useLines {lines ->
lines.forEach {
val datum = it.toInt()
log("Read $datum")
yield(datum)
}
}
}
}
fun processData(filename: String) {
for (datum in readData(filename)) {
log("Processing data $datum")
}
}
Coroutine Solution
fun readData(filename: String): List<Int> {
val data = mutableListOf<Int>()
File(filename).useLines {lines ->
lines.forEach {
val datum = it.toInt()
log("Read $datum")
data.add(datum)
}
}
return data
}
Coroutine Solution
fun readData(filename: String): Sequence<Int> {
return sequence {
File(filename).useLines {lines ->
lines.forEach {
val datum = it.toInt()
log("Read $datum")
yield(datum)
}
}
}
} return
suspend
Let’s get technical
“Coroutines are computer-program components
that generalize subroutines for non-preemptive
multitasking, by allowing multiple entry points for
suspending and resuming execution at certain
locations.”
Wikipedia
Coroutine
1 1 2 2 3 3 4 4 5 5 6 6 7 7
1
1
2
2
3
3
4
4
5
5
6
6
7
7
“Coroutines simplify writing code that needs to
suspend and resume. e.g. generators,
asynchronous code, event loops etc
You write it like standard sequential code (more or
less) but under the hood it returns/suspends and
reenters/resumes. ”
Eamonn Boyle
Coroutine
..using Magic!!
They do not help us write faster code
• Although they can help us write more efficient systems
• This may make the whole system more responsive
It is easier to write as it is very similar to standard code
We get to use all the standard coding elements we are used to
• if, for, while
• try-catch
• function calls
• Etc
Benefits of Coroutines
Consider 3 independent jobs of work
Event Loop with Asynchronous Blocks
Start 5 6EndBlocking Start 5 6EndBlocking Start 5 6EndBlocking
fun workSync(message: String) {
log("$message started")
Thread.sleep(sleepTime)
log("$message ended")
}
jobs.forEach {
workSync(it)
}
[1]: Running Synchronous
[1]: Job 1 started
[1]: Job 1 ended
[1]: Job 2 started
[1]: Job 2 ended
[1]: Job 3 started
[1]: Job 3 ended
[1]: Synchronous took 15003 ms
Consider 3 independent jobs of work
Event Loop with Asynchronous Blocks
Start 5 6EndBlocking Start 5 6EndBlocking Start 5 6EndBlocking
Start 5 6EndBlocking
Start 5 6EndBlocking
Start 5 6EndBlocking
If we want to run these in parallel we could create multiple threads
jobs.map {
val thread = Thread {
workSync(it)
}
thread.start()
thread
}.forEach {
log("Joining thread ${it.id}")
it.join()
}
[1]: Running Parallel Threads
[1]: Joining with thread 12
[12]: Job 1 started
[14]: Job 3 started
[13]: Job 2 started
[13]: Job 2 ended
[12]: Job 1 ended
[14]: Job 3 ended
[1]: Joining with thread 13
[1]: Joining with thread 14
[1]: Parallel Threads took 5004 ms
There are scalability issues - threads are heavy
Startup times can be slow
The syntax is clunky
Optimal Usage of Fewer Threads
Start End
Blocking
Start End
Blocking
Start 5 6End
Blocking
Asynchronous Use Case – Thread Pools
Start End
Blocking
Start End
Blocking
Start 5 6End
Blocking
Asynchronous Use Case – Thread Dispatching
Start
EndBlocking
Start
EndBlocking
Start
5 6EndBlocking
Asynchronous Use Case – Common Characteristics
Start EndStart EndStart 5 6End
Quite often we must use certain threads for certain work
• E.g. UI typically has a single main thread
Quite often the asynchronous work can be optimised
• Event interrupts for I/O
• Single polling thread for multiple elements
• Pooling certain work on dedicated worker threads
fun mySleep(time: Long, action: () -> Unit): CompletableFuture<Unit> {
return CompletableFuture.runAsync {
Thread.sleep(time)
}.thenApply { action() }
}
fun workSync(message: String): CompletableFuture<Unit> {
log("$message started")
return mySleep(sleepTime) {
log("$message ended")
}
}
jobs.map {
workSync(it)
}.forEach {
it.join()
}
Callbacks & CompletableFuture Solution
fun mySleep(time: Long, action: () -> Unit): CompletableFuture<Unit> {
return CompletableFuture.runAsync {
Thread.sleep(time)
}.thenApply { action() }
}
fun workSync(message: String): CompletableFuture<Unit> {
log("$message started")
return mySleep(sleepTime) {
log("$message ended")
}
}
jobs.map {
workSync(it)
}.forEach {
it.join()
}
[1]: Running Synchronous
[1]: Job 1 started
[1]: Job 2 started
[1]: Job 3 started
[12]: Job 1 ended
[13]: Job 2 ended
[14]: Job 3 ended
[1]: Synchronous took 5018 ms
CompletableFuture Solution
CompletableFuture Solution
Start
EndBlocking
Start
EndBlocking
Start
5 6EndBlocking
fun workSync(message: String) {
log("$message started")
Thread.sleep(sleepTime)
log("$message ended")
}
jobs.forEach {
workSync(it)
}
Coroutine Solution
suspend fun workAsync(message: String) {
log("$message started")
delay(sleepTime)
log("$message ended")
}
runBlocking {
jobs.map {
launch {
workAsync(it)
}
}.joinAll()
}
Coroutine Solution
suspend fun workAsync(message: String) {
log("$message started")
delay(sleepTime)
log("$message ended")
}
runBlocking {
jobs.map {
launch {
workAsync(it)
}
}.joinAll()
}
[1]: Running Coroutines
[1]: Job 1 started
[1]: Job 2 started
[1]: Job 3 started
[1]: Job 1 ended
[1]: Job 2 ended
[1]: Job 3 ended
[1]: Coroutines took 5161 ms
Asynchronous Coroutines
Start End
Blocking
Start End
Blocking
Start 5 6End
Blocking
fun workSync(message: String) {
log("$message started")
Thread.sleep(sleepTime)
log("$message ended")
}
suspend fun workAsync(message: String) {
log("$message started")
delay(sleepTime)
log("$message ended")
}
Suspend Functions
fun workSync(message: String) {
log("$message started")
Thread.sleep(sleepTime)
log("$message ended")
}
Suspend Functions
suspend fun workAsync(message: String) {
log("$message started")
delay(sleepTime)
log("$message ended")
}
fun workSync(message: String) {
log("$message started")
Thread.sleep(sleepTime)
log("$message ended")
}
Suspend Functions
suspend fun workAsync(message: String) {
log("$message started")
delay(sleepTime)
log("$message ended")
}
This is a suspension
point
Asynchronous Coroutines
Start End
Blocking
Start End
Blocking
Start 5 6End
Blocking
Coroutines as Light Weight Threads
Start EndBlocking
Start EndBlocking
Start 5 6EndBlocking
Coroutines Scale
Start EndBlocking
Start EndBlocking
Start 5 6EndBlocking
Start EndBlocking
Start EndBlocking
Start 5 6EndBlocking
Start EndBlocking
2019-01-29 - Demystifying Kotlin Coroutines
Asynchronous Coroutines
Start End
Blocking
Start End
Blocking
Start 5 6End
Blocking
Asynchronous Coroutines
Start End
Blocking
Start End
Blocking
Start 5 6End
Blocking
suspend fun doWork() {
val a = step1()
step2()
val b = step3()
val total = a + b
log("The sum is $total")
}
Another Example
suspend fun doWork() {
val a = step1()
step2()
val b = step3()
val total = a + b
log("The sum is $total")
}
fun doWork(): CompletableFuture<Unit> {
return step1().thenCompose { a ->
step2().thenCompose {
step3().thenApply { b ->
val total = a + b
log("The sum is $total")
}
}
}
}
Coroutine as Completable
suspend fun doWork() {
val a = step1()
step2()
val b = step3()
val total = a + b
log("The sum is $total")
}
class SimpleCouroutineDoWork {
var label = 0
var a: Int? = null
var b: Int? = null
var total: Int? = null
fun resumeWith(...) {
}
}
Coroutine Implementation – State Machine
This class is the continuation
It represents the state of a suspending function
Coroutine Implementation – State Machine
suspend fun doWork() {
val a = step1()
step2()
val b = step3()
val total = a + b
log("The sum is $total")
}
fun resumeWith(result: Result<Any>) {
var newResult = result.getOrThrow()
if (label == 0) {
newResult = step1(this)
label = 1
if (newResult == COROUTINE_SUSPENDED) return
}
if (label == 1) {
a = newResult as Int
newResult = step2(this)
label = 2
if (newResult == COROUTINE_SUSPENDED) return
}
if (label == 2) {
b = newResult as Int
newResult = step3(this)
label = 3
if (newResult == COROUTINE_SUSPENDED) return
}
if (label == 4) {
total = a!! + b!!
log("The sum is $total")
}
}
suspend fun doWork() {
val a = step1()
step2()
val b = step3()
val total = a + b
log("The sum is $total")
}
fun resumeWith(result: Result<Any>) {
var newResult = result.getOrThrow()
if (label == 0) {
newResult = step1(this)
label = 1
if (newResult == COROUTINE_SUSPENDED) {
return
}
}
if (label == 1) {
a = newResult as Int
newResult = step2(this)
...
This is mainly for efficiency reasons
Less objects created to handle the context switching
Coroutine Implementation – State Machine
suspend fun doWork() {
val a = step1()
step2()
val b = step3()
val total = a + b
log("The sum is $total")
}
suspend fun step1() {
log("Step 1 started")
delay(1000)
log("Step 1 ended")
}
Coroutine – Suspend Functions Calling Each Other
Note, a suspend function is not a coroutine
• They are used to write parts of a coroutine
• They cannot be called from normal functions
A corountine is suspendable, sequential computation
It is similar to a thread but is not bound to any particular thread
• It can be created, started and ended
• It can suspend on one thread and resume on another
• It can return a result
Coroutine Builders
The compiler translates our suspend functions
The standard library provides only a primitive API
• This is very much by design
Using these fundamental building blocks, libraries add functionality
This add a lot of flexibility
• Consider different platforms – JVM, JS, Native
• Consider different use cases – generators, async await, actors
• We can add various different threading strategies
Coroutine APIs
© Instil Software 2019
• Practical Coroutine Usage
kotlinx.corountines
kotlinx.coroutines adds the API entitles for useful coroutines
Scope – Encloses a coroutines and its child coroutines
Context – A key/value collection of values to control execution
Dispatcher – Controls coroutine execution e.g. which threads to use
Builders – functions to create a coroutine
Interceptor – Wraps/intercepts coroutine execution
Bridge – A builder that can be called from a non-suspend function
Coroutine Builders
Controls which thread is used to execute a continuation
• A scope with its context will define a dispatcher
These will be platform dependent but exists in Dispatchers object
Coroutine Dispatchers
Dispatcher Description
Default Executes on a default background thread pool
Unconfined Executes using any available thread
Main Executes on the Main (UI) thread
IO Executes blocking I/O calls. Shares threads with Default
but will create and shutdown additional threads
Any standard Java Executor Service can become a dispatcher
• Simply invoke the ‘asCoroutineDispatcher’ extension method
Other dedicated functions exist but these are going to be replaced
Using a Custom Coroutine Dispatcher
fun runDemoViaCustomThreadPool(name: String) {
val threadPool = Executors.newFixedThreadPool(2)
val dispatcher = threadPool.asCoroutineDispatcher()
runBlocking(dispatcher) {
// ...
}
threadPool.shutdown()
}
These are functions that are supplied a suspend function/lambda
and creates a coroutine
Coroutine Builders
Builder Description
launch Returns a Job object representing the coroutine but is largely fire
and forget. It is synchronised with another coroutine using join.
async Returns a Deferred<T> object which is an extension of Job that
includes a result. The result is acquired using await.
runBlocking Runs a coroutine and blocks the current thread until it completes
sequence Creates generators using a suspend function
These suspending functions execute against a Coroutine Scope
• They are extension methods of CoroutineScope
Suspending Functions
Builder Description
delay Executes a non-blocking sleep
yield Yields the thread in single thread disaptchers
withContext Like runBlocking within a coroutine i.e. it suspends
withTimeout Sets a time limit on execution of a function
await, awaitAll Waits for one or multiple Deferred to complete and returns
the result/s
join, joinAll Waits for one or multiple jobs to complete
class MyActivity : AppCompatActivity(), CoroutineScope {
lateinit var job: Job
override val coroutineContext: CoroutineContext
get() = Dispatchers.Main + job
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
job = Job()
}
override fun onDestroy() {
super.onDestroy()
job.cancel() // Cancel job on activity destroy. After Destroy
// all children jobs will be cancelled automatically
}
https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/
Android Activity
class MyActivity : AppCompatActivity(), CoroutineScope {
lateinit var job: Job
override val coroutineContext: CoroutineContext
get() = Dispatchers.Main + job
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
job = Job()
}
override fun onDestroy() {
super.onDestroy()
job.cancel() // Cancel job on activity destroy. After Destroy
// all children jobs will be cancelled automatically
}
https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/
Android Activity
fun loadDataFromUI() = launch { // this (Main) Dispatcher
val ioData = async(Dispatchers.IO) { // IO Dispatcher
// blocking I/O operation
}
// Work here will execute in parallel to IO
// It will run on the Main thread
val data = ioData.await() // Wait for result of I/O
// Complete work in Main thread
}
Android Activity
https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/
fun voidPayment(tender: CheckTender) = launch(Dispatchers.Default) {
when (tender.type) {
CREDIT, MANUAL_CREDIT -> voidCreditPayment(tender)
GIFT_CARD, MANUAL_GIFT_CARD -> voidGiftCardPayment(tender)
else -> onVoidFailed()
}
}
suspend fun voidCreditPayment(tender: CheckTender) {
try {
val voidPaymentResponse = voidService.voidPayment().await()
when (voidPaymentResponse.result) {
SUCCESS -> onCreditVoidSuccess(tender, voidPaymentResponse)
else -> onCreditVoidFailed(tender, voidPaymentResponse)
}
} catch (throwable: Throwable) {
onVoidFailed()
}
}
Coroutines went stable in 1.3
Similar things exist in other languages
• E.g. async await has been in C# since 2014, F# since 2012
• JavaScript, Python have very similar syntax to C#
• Golang has goroutines & channels
• They are all very useful at simplifying your code
We now have a great solution for the JVM (and others)
The Kotlin solution is built from primitives that open up flexibility
Summary
Questions?
https://github.com/Kotlin/KEEP/blob/master/proposals/coroutines.md
https://github.com/Kotlin/kotlinx.coroutines
https://www.imdb.com
References

More Related Content

PDF
The Ring programming language version 1.5.2 book - Part 39 of 181
PDF
The Ring programming language version 1.5.2 book - Part 11 of 181
PPTX
Psycopg2 - Connect to PostgreSQL using Python Script
PDF
Dynomite Nosql
PDF
The Ring programming language version 1.5.4 book - Part 40 of 185
PDF
Programming with Python and PostgreSQL
PPTX
Python database interfaces
PPTX
EX-6-Implement Matrix Multiplication with Hadoop Map Reduce.pptx
The Ring programming language version 1.5.2 book - Part 39 of 181
The Ring programming language version 1.5.2 book - Part 11 of 181
Psycopg2 - Connect to PostgreSQL using Python Script
Dynomite Nosql
The Ring programming language version 1.5.4 book - Part 40 of 185
Programming with Python and PostgreSQL
Python database interfaces
EX-6-Implement Matrix Multiplication with Hadoop Map Reduce.pptx

What's hot (20)

PDF
concurrency with GPars
ODP
GPars (Groovy Parallel Systems)
PDF
Utilizing Powerful Extensions for Analytics and Operations
PPTX
Php sql-android
PDF
Presto in Treasure Data
PDF
"PostgreSQL and Python" Lightning Talk @EuroPython2014
PDF
JavaScript ∩ WebAssembly
PDF
Py spark cheat sheet by cheatsheetmaker.com
PPTX
Apache Flink Training: DataSet API Basics
PDF
A Practical Introduction to Handling Log Data in ClickHouse, by Robert Hodges...
PDF
Kitura Todolist tutorial
PDF
The Ring programming language version 1.9 book - Part 48 of 210
PDF
AJUG April 2011 Raw hadoop example
PDF
Obtaining the Perfect Smoke By Monitoring Your BBQ with InfluxDB and Telegraf
PDF
Monitoring Your ISP Using InfluxDB Cloud and Raspberry Pi
PDF
Full Text Search In PostgreSQL
PDF
Cassandra summit 2013 - DataStax Java Driver Unleashed!
PPTX
Apache Flink Training: DataStream API Part 2 Advanced
PDF
Accelerating Local Search with PostgreSQL (KNN-Search)
PDF
XML-Motor
concurrency with GPars
GPars (Groovy Parallel Systems)
Utilizing Powerful Extensions for Analytics and Operations
Php sql-android
Presto in Treasure Data
"PostgreSQL and Python" Lightning Talk @EuroPython2014
JavaScript ∩ WebAssembly
Py spark cheat sheet by cheatsheetmaker.com
Apache Flink Training: DataSet API Basics
A Practical Introduction to Handling Log Data in ClickHouse, by Robert Hodges...
Kitura Todolist tutorial
The Ring programming language version 1.9 book - Part 48 of 210
AJUG April 2011 Raw hadoop example
Obtaining the Perfect Smoke By Monitoring Your BBQ with InfluxDB and Telegraf
Monitoring Your ISP Using InfluxDB Cloud and Raspberry Pi
Full Text Search In PostgreSQL
Cassandra summit 2013 - DataStax Java Driver Unleashed!
Apache Flink Training: DataStream API Part 2 Advanced
Accelerating Local Search with PostgreSQL (KNN-Search)
XML-Motor
Ad

Similar to 2019-01-29 - Demystifying Kotlin Coroutines (20)

PPTX
Kotlin coroutines and spring framework
PDF
Coroutines in Kotlin. In-depth review
PDF
Coroutines in Kotlin. UA Mobile 2017.
PDF
Dip into Coroutines - KTUG Munich 202303
PDF
Kotlin Advanced - Apalon Kotlin Sprint Part 3
PPTX
Coroutines talk ppt
PDF
Kotlin Coroutines and Android sitting in a tree
PDF
Asynchronous Programming in Kotlin with Coroutines
PPTX
Design patterns with kotlin
PDF
Quick Introduction to Kotlin Coroutine for Android Dev
PDF
Programação assíncrona utilizando Coroutines
PDF
Should it be routine to use coroutines?
PPTX
Exploring Kotlin
PDF
Kotlin for android developers whats new
PDF
Coroutines in Kotlin
PDF
TDC2018SP | Trilha Kotlin - Programacao assincrona utilizando Coroutines
PDF
Introduction to Coroutines @ KotlinConf 2017
PPTX
Coroutines in Kotlin
PDF
JVMLS 2016. Coroutines in Kotlin
PDF
Introduction to kotlin coroutines
Kotlin coroutines and spring framework
Coroutines in Kotlin. In-depth review
Coroutines in Kotlin. UA Mobile 2017.
Dip into Coroutines - KTUG Munich 202303
Kotlin Advanced - Apalon Kotlin Sprint Part 3
Coroutines talk ppt
Kotlin Coroutines and Android sitting in a tree
Asynchronous Programming in Kotlin with Coroutines
Design patterns with kotlin
Quick Introduction to Kotlin Coroutine for Android Dev
Programação assíncrona utilizando Coroutines
Should it be routine to use coroutines?
Exploring Kotlin
Kotlin for android developers whats new
Coroutines in Kotlin
TDC2018SP | Trilha Kotlin - Programacao assincrona utilizando Coroutines
Introduction to Coroutines @ KotlinConf 2017
Coroutines in Kotlin
JVMLS 2016. Coroutines in Kotlin
Introduction to kotlin coroutines
Ad

More from Eamonn Boyle (8)

PPTX
Kotlin for Android - Goto Copenhagan 2019
PPTX
Kotlin Native - C / Swift Interop - ACCU Autmn 2019
PPTX
2019-06 - Goto Amsterdam - Microservices
PPTX
Kotlin for all the Things
PPTX
BelTech 2017 - Building Quality in the Browser
PPTX
ASP .Net Core SPA Templates
PPTX
Being Expressive in Code
PPTX
2018-09 - F# and Fable
Kotlin for Android - Goto Copenhagan 2019
Kotlin Native - C / Swift Interop - ACCU Autmn 2019
2019-06 - Goto Amsterdam - Microservices
Kotlin for all the Things
BelTech 2017 - Building Quality in the Browser
ASP .Net Core SPA Templates
Being Expressive in Code
2018-09 - F# and Fable

Recently uploaded (20)

PPTX
CHAPTER 2 - PM Management and IT Context
PPTX
ai tools demonstartion for schools and inter college
PDF
Why TechBuilder is the Future of Pickup and Delivery App Development (1).pdf
PDF
Navsoft: AI-Powered Business Solutions & Custom Software Development
PPTX
Transform Your Business with a Software ERP System
PPTX
Operating system designcfffgfgggggggvggggggggg
PPTX
ManageIQ - Sprint 268 Review - Slide Deck
PDF
Raksha Bandhan Grocery Pricing Trends in India 2025.pdf
PDF
Internet Downloader Manager (IDM) Crack 6.42 Build 42 Updates Latest 2025
PDF
top salesforce developer skills in 2025.pdf
PPTX
Agentic AI Use Case- Contract Lifecycle Management (CLM).pptx
PDF
Which alternative to Crystal Reports is best for small or large businesses.pdf
PPTX
Lecture 3: Operating Systems Introduction to Computer Hardware Systems
PDF
Addressing The Cult of Project Management Tools-Why Disconnected Work is Hold...
PDF
Digital Strategies for Manufacturing Companies
PDF
System and Network Administration Chapter 2
PDF
How Creative Agencies Leverage Project Management Software.pdf
PDF
2025 Textile ERP Trends: SAP, Odoo & Oracle
PDF
SAP S4 Hana Brochure 3 (PTS SYSTEMS AND SOLUTIONS)
PPTX
Introduction to Artificial Intelligence
CHAPTER 2 - PM Management and IT Context
ai tools demonstartion for schools and inter college
Why TechBuilder is the Future of Pickup and Delivery App Development (1).pdf
Navsoft: AI-Powered Business Solutions & Custom Software Development
Transform Your Business with a Software ERP System
Operating system designcfffgfgggggggvggggggggg
ManageIQ - Sprint 268 Review - Slide Deck
Raksha Bandhan Grocery Pricing Trends in India 2025.pdf
Internet Downloader Manager (IDM) Crack 6.42 Build 42 Updates Latest 2025
top salesforce developer skills in 2025.pdf
Agentic AI Use Case- Contract Lifecycle Management (CLM).pptx
Which alternative to Crystal Reports is best for small or large businesses.pdf
Lecture 3: Operating Systems Introduction to Computer Hardware Systems
Addressing The Cult of Project Management Tools-Why Disconnected Work is Hold...
Digital Strategies for Manufacturing Companies
System and Network Administration Chapter 2
How Creative Agencies Leverage Project Management Software.pdf
2025 Textile ERP Trends: SAP, Odoo & Oracle
SAP S4 Hana Brochure 3 (PTS SYSTEMS AND SOLUTIONS)
Introduction to Artificial Intelligence

2019-01-29 - Demystifying Kotlin Coroutines

  • 1. training@instil.co January 2019 © Instil Software 2019 Demystifying Kotlin Coroutines GDG Dublin @BoyleEamonn Eamonn Boyle
  • 2. Me
  • 3. Us
  • 5. We’ve really bought into Kotlin Kotlin Conf 2018
  • 6. We held a workshop at the conference • React Web App with Kotlin on Server & Browser Kotlin Conf 2018
  • 12. Long Story Short - Synchronous is Easy fun doWork() { disableUI() val exchangeRates = readExchangeRate() val report = buildReport(exchangeRates) saveReport(report) enableUI() } 1 2 3 4 5 imdb.com return
  • 13. Long Story Short - Synchronous is Easy fun doWork() { disableUI() val exchangeRates = readExchangeRate() val report = buildReport(exchangeRates) saveReport(report) enableUI() } 1 2 3 4 5 We can’t escape asynchronous programming Typically we can’t block due to limited resources But we want ways to hide the complexity of async
  • 14. Long Story Short – Callback Hell fun doWork() { disableUI() readExchangeRate { exchangeRate -> buildReport(exchangeRate) { report -> saveReport(report) { enableUI() } } } } imdb.com return
  • 15. Long Story Short – Futures Help fun doWork() { disableUI() readExchangeRate() .thenCompose(::buildReport) .thenCompose(::saveReport) .thenApply { enableUI() } } imdb.com Once you’ve learned the complete API, then you have my permission to die return
  • 16. Long Story Short – Coroutines Are Better suspend fun doWork() { disableUI() val exchangeRates = readExchangeRate() val report = buildReport(exchangeRates) saveReport(report) enableUI() } imdb.com suspend suspend suspend return
  • 17. Long Story Short – Coroutines Are Better suspend fun doWork() { disableUI() val exchangeRates = readExchangeRate() val report = buildReport(exchangeRates) saveReport(report) enableUI() } fun doWork() { disableUI() val exchangeRates = readExchangeRate() val report = buildReport(exchangeRates) saveReport(report) enableUI() }
  • 18. Long Story Short – Control Dispatch suspend fun doWorkWithThreadControl() { disableUI() withContext(Dispatchers.IO) { val exchangeRates = readExchangeRate() val report = buildReport(exchangeRates) saveReport(report) } enableUI() }
  • 20. Generator Use Case 1 2 3 4 5 6 7 1 2 3 4 5 6 7 Reading Processing fun readData(filename: String): List<Int> { val data = mutableListOf<Int>() File(filename).useLines {lines -> lines.forEach { val datum = it.toInt() log("Read $datum") data.add(datum) } } return data } fun processData(filename: String) { for (datum in readData(filename)) { log("Processing data $datum") } }
  • 21. fun readData(filename: String): List<Int> { val data = mutableListOf<Int>() File(filename).useLines {lines -> lines.forEach { val datum = it.toInt() log("Read $datum") data.add(datum) } } return data } fun processData(filename: String) { val data = readData(filename) for (datum in data) { log("Processing data $datum") } }
  • 22. fun readData(filename: String): List<Int> { val data = mutableListOf<Int>() File(filename).useLines {lines -> lines.forEach { val datum = it.toInt() log("Read $datum") data.add(datum) } } return data } fun processData(filename: String) { val data = readData(filename) for (datum in data) { log("Processing data $datum") } }
  • 23. fun readData(filename: String): List<Int> { val data = mutableListOf<Int>() File(filename).useLines {lines -> lines.forEach { val datum = it.toInt() log("Read $datum") data.add(datum) } } return data } fun processData(filename: String) { val data = readData(filename) for (datum in data) { log("Processing data $datum") } } What if the read takes too long? What if the amount of data read is too large?
  • 24. We may need to interleave reading and processing How should we implement this? Perhaps hand code the interleaving • Perhaps use standard interfaces to simplify Generator Use Case 1 2 3 4 5 6 7 1 2 3 4 5 6 7 Reading Function Processing Function 1 1 2 2 3 3 4 4 5 5 6 6 7 7
  • 25. class CustomInterleaved(filename: String) { val file = File(filename) .inputStream() .bufferedReader() fun readData(): Int { val line = file.readLine() if (line == null) { file.close() return -1 } val datum = line.toInt() log("Read $datum") return datum } } Manual Interleaving fun processData(filename: String) { val interleaved = CustomInterleaved(filename) while (true) { val datum = interleaved.readData() if (datum < 0) { break } log("Processing data $datum") } }
  • 26. class CustomInterleaved(filename: String) { val file = File(filename) .inputStream() .bufferedReader() fun readData(): Int { val line = file.readLine() if (line == null) { file.close() return -1 } val datum = line.toInt() log("Read $datum") return datum } } Manual Interleaving fun processData(filename: String) { val interleaved = CustomInterleaved(filename) while (true) { val datum = interleaved.readData() if (datum < 0) { break } log("Processing data $datum") } }
  • 27. class CustomIterable(val filename: String) : Iterable<Int>, AutoCloseable { val file = File(filename).inputStream().bufferedReader() class CustomIterator(val file: BufferedReader) : Iterator<Int> { override fun next(): Int { val datum = file.readLine().toInt() log("Read $datum") return datum } override fun hasNext(): Boolean = file.ready() } override fun iterator(): Iterator<Int> = CustomIterator(file) override fun close() = log("Closing file") } Standard Idioms – Iterable Interface
  • 28. class CustomIterable(val filename: String) : Iterable<Int>, AutoCloseable { val file = File(filename).inputStream().bufferedReader() class CustomIterator(val file: BufferedReader) : Iterator<Int> { override fun next(): Int { val datum = file.readLine().toInt() log("Read $datum") return datum } override fun hasNext(): Boolean = file.ready() } override fun iterator(): Iterator<Int> = CustomIterator(file) override fun close() = log("Closing file") } Standard Idioms – Iterable Interface
  • 29. fun processData(filename: String) { CustomIterable(filename).use {data -> for (datum in data) { log("Processing data $datum") } } } Benefit – Simpler Usage
  • 30. fun readData(filename: String): List<Int> { val data = mutableListOf<Int>() File(filename).useLines {lines -> lines.forEach { val datum = it.toInt() log("Read $datum") data.add(datum) } } return data } fun processData(filename: String) { for (datum in readData(filename)) { log("Processing data $datum") } } fun readData(filename: String): Sequence<Int> { return sequence { File(filename).useLines {lines -> lines.forEach { val datum = it.toInt() log("Read $datum") yield(datum) } } } } fun processData(filename: String) { for (datum in readData(filename)) { log("Processing data $datum") } } Coroutine Solution
  • 31. fun readData(filename: String): List<Int> { val data = mutableListOf<Int>() File(filename).useLines {lines -> lines.forEach { val datum = it.toInt() log("Read $datum") data.add(datum) } } return data } Coroutine Solution fun readData(filename: String): Sequence<Int> { return sequence { File(filename).useLines {lines -> lines.forEach { val datum = it.toInt() log("Read $datum") yield(datum) } } } } return suspend
  • 33. “Coroutines are computer-program components that generalize subroutines for non-preemptive multitasking, by allowing multiple entry points for suspending and resuming execution at certain locations.” Wikipedia Coroutine
  • 34. 1 1 2 2 3 3 4 4 5 5 6 6 7 7
  • 36. “Coroutines simplify writing code that needs to suspend and resume. e.g. generators, asynchronous code, event loops etc You write it like standard sequential code (more or less) but under the hood it returns/suspends and reenters/resumes. ” Eamonn Boyle Coroutine ..using Magic!!
  • 37. They do not help us write faster code • Although they can help us write more efficient systems • This may make the whole system more responsive It is easier to write as it is very similar to standard code We get to use all the standard coding elements we are used to • if, for, while • try-catch • function calls • Etc Benefits of Coroutines
  • 38. Consider 3 independent jobs of work Event Loop with Asynchronous Blocks Start 5 6EndBlocking Start 5 6EndBlocking Start 5 6EndBlocking fun workSync(message: String) { log("$message started") Thread.sleep(sleepTime) log("$message ended") } jobs.forEach { workSync(it) } [1]: Running Synchronous [1]: Job 1 started [1]: Job 1 ended [1]: Job 2 started [1]: Job 2 ended [1]: Job 3 started [1]: Job 3 ended [1]: Synchronous took 15003 ms
  • 39. Consider 3 independent jobs of work Event Loop with Asynchronous Blocks Start 5 6EndBlocking Start 5 6EndBlocking Start 5 6EndBlocking Start 5 6EndBlocking Start 5 6EndBlocking Start 5 6EndBlocking If we want to run these in parallel we could create multiple threads
  • 40. jobs.map { val thread = Thread { workSync(it) } thread.start() thread }.forEach { log("Joining thread ${it.id}") it.join() } [1]: Running Parallel Threads [1]: Joining with thread 12 [12]: Job 1 started [14]: Job 3 started [13]: Job 2 started [13]: Job 2 ended [12]: Job 1 ended [14]: Job 3 ended [1]: Joining with thread 13 [1]: Joining with thread 14 [1]: Parallel Threads took 5004 ms There are scalability issues - threads are heavy Startup times can be slow The syntax is clunky
  • 41. Optimal Usage of Fewer Threads Start End Blocking Start End Blocking Start 5 6End Blocking
  • 42. Asynchronous Use Case – Thread Pools Start End Blocking Start End Blocking Start 5 6End Blocking
  • 43. Asynchronous Use Case – Thread Dispatching Start EndBlocking Start EndBlocking Start 5 6EndBlocking
  • 44. Asynchronous Use Case – Common Characteristics Start EndStart EndStart 5 6End Quite often we must use certain threads for certain work • E.g. UI typically has a single main thread Quite often the asynchronous work can be optimised • Event interrupts for I/O • Single polling thread for multiple elements • Pooling certain work on dedicated worker threads
  • 45. fun mySleep(time: Long, action: () -> Unit): CompletableFuture<Unit> { return CompletableFuture.runAsync { Thread.sleep(time) }.thenApply { action() } } fun workSync(message: String): CompletableFuture<Unit> { log("$message started") return mySleep(sleepTime) { log("$message ended") } } jobs.map { workSync(it) }.forEach { it.join() } Callbacks & CompletableFuture Solution
  • 46. fun mySleep(time: Long, action: () -> Unit): CompletableFuture<Unit> { return CompletableFuture.runAsync { Thread.sleep(time) }.thenApply { action() } } fun workSync(message: String): CompletableFuture<Unit> { log("$message started") return mySleep(sleepTime) { log("$message ended") } } jobs.map { workSync(it) }.forEach { it.join() } [1]: Running Synchronous [1]: Job 1 started [1]: Job 2 started [1]: Job 3 started [12]: Job 1 ended [13]: Job 2 ended [14]: Job 3 ended [1]: Synchronous took 5018 ms CompletableFuture Solution
  • 48. fun workSync(message: String) { log("$message started") Thread.sleep(sleepTime) log("$message ended") } jobs.forEach { workSync(it) } Coroutine Solution suspend fun workAsync(message: String) { log("$message started") delay(sleepTime) log("$message ended") } runBlocking { jobs.map { launch { workAsync(it) } }.joinAll() }
  • 49. Coroutine Solution suspend fun workAsync(message: String) { log("$message started") delay(sleepTime) log("$message ended") } runBlocking { jobs.map { launch { workAsync(it) } }.joinAll() } [1]: Running Coroutines [1]: Job 1 started [1]: Job 2 started [1]: Job 3 started [1]: Job 1 ended [1]: Job 2 ended [1]: Job 3 ended [1]: Coroutines took 5161 ms
  • 50. Asynchronous Coroutines Start End Blocking Start End Blocking Start 5 6End Blocking
  • 51. fun workSync(message: String) { log("$message started") Thread.sleep(sleepTime) log("$message ended") } suspend fun workAsync(message: String) { log("$message started") delay(sleepTime) log("$message ended") } Suspend Functions
  • 52. fun workSync(message: String) { log("$message started") Thread.sleep(sleepTime) log("$message ended") } Suspend Functions suspend fun workAsync(message: String) { log("$message started") delay(sleepTime) log("$message ended") }
  • 53. fun workSync(message: String) { log("$message started") Thread.sleep(sleepTime) log("$message ended") } Suspend Functions suspend fun workAsync(message: String) { log("$message started") delay(sleepTime) log("$message ended") } This is a suspension point
  • 54. Asynchronous Coroutines Start End Blocking Start End Blocking Start 5 6End Blocking
  • 55. Coroutines as Light Weight Threads Start EndBlocking Start EndBlocking Start 5 6EndBlocking
  • 56. Coroutines Scale Start EndBlocking Start EndBlocking Start 5 6EndBlocking Start EndBlocking Start EndBlocking Start 5 6EndBlocking Start EndBlocking
  • 58. Asynchronous Coroutines Start End Blocking Start End Blocking Start 5 6End Blocking
  • 59. Asynchronous Coroutines Start End Blocking Start End Blocking Start 5 6End Blocking
  • 60. suspend fun doWork() { val a = step1() step2() val b = step3() val total = a + b log("The sum is $total") } Another Example
  • 61. suspend fun doWork() { val a = step1() step2() val b = step3() val total = a + b log("The sum is $total") } fun doWork(): CompletableFuture<Unit> { return step1().thenCompose { a -> step2().thenCompose { step3().thenApply { b -> val total = a + b log("The sum is $total") } } } } Coroutine as Completable
  • 62. suspend fun doWork() { val a = step1() step2() val b = step3() val total = a + b log("The sum is $total") } class SimpleCouroutineDoWork { var label = 0 var a: Int? = null var b: Int? = null var total: Int? = null fun resumeWith(...) { } } Coroutine Implementation – State Machine This class is the continuation It represents the state of a suspending function
  • 63. Coroutine Implementation – State Machine suspend fun doWork() { val a = step1() step2() val b = step3() val total = a + b log("The sum is $total") } fun resumeWith(result: Result<Any>) { var newResult = result.getOrThrow() if (label == 0) { newResult = step1(this) label = 1 if (newResult == COROUTINE_SUSPENDED) return } if (label == 1) { a = newResult as Int newResult = step2(this) label = 2 if (newResult == COROUTINE_SUSPENDED) return } if (label == 2) { b = newResult as Int newResult = step3(this) label = 3 if (newResult == COROUTINE_SUSPENDED) return } if (label == 4) { total = a!! + b!! log("The sum is $total") } }
  • 64. suspend fun doWork() { val a = step1() step2() val b = step3() val total = a + b log("The sum is $total") } fun resumeWith(result: Result<Any>) { var newResult = result.getOrThrow() if (label == 0) { newResult = step1(this) label = 1 if (newResult == COROUTINE_SUSPENDED) { return } } if (label == 1) { a = newResult as Int newResult = step2(this) ... This is mainly for efficiency reasons Less objects created to handle the context switching Coroutine Implementation – State Machine
  • 65. suspend fun doWork() { val a = step1() step2() val b = step3() val total = a + b log("The sum is $total") } suspend fun step1() { log("Step 1 started") delay(1000) log("Step 1 ended") } Coroutine – Suspend Functions Calling Each Other
  • 66. Note, a suspend function is not a coroutine • They are used to write parts of a coroutine • They cannot be called from normal functions A corountine is suspendable, sequential computation It is similar to a thread but is not bound to any particular thread • It can be created, started and ended • It can suspend on one thread and resume on another • It can return a result Coroutine Builders
  • 67. The compiler translates our suspend functions The standard library provides only a primitive API • This is very much by design Using these fundamental building blocks, libraries add functionality This add a lot of flexibility • Consider different platforms – JVM, JS, Native • Consider different use cases – generators, async await, actors • We can add various different threading strategies Coroutine APIs
  • 68. © Instil Software 2019 • Practical Coroutine Usage kotlinx.corountines
  • 69. kotlinx.coroutines adds the API entitles for useful coroutines Scope – Encloses a coroutines and its child coroutines Context – A key/value collection of values to control execution Dispatcher – Controls coroutine execution e.g. which threads to use Builders – functions to create a coroutine Interceptor – Wraps/intercepts coroutine execution Bridge – A builder that can be called from a non-suspend function Coroutine Builders
  • 70. Controls which thread is used to execute a continuation • A scope with its context will define a dispatcher These will be platform dependent but exists in Dispatchers object Coroutine Dispatchers Dispatcher Description Default Executes on a default background thread pool Unconfined Executes using any available thread Main Executes on the Main (UI) thread IO Executes blocking I/O calls. Shares threads with Default but will create and shutdown additional threads
  • 71. Any standard Java Executor Service can become a dispatcher • Simply invoke the ‘asCoroutineDispatcher’ extension method Other dedicated functions exist but these are going to be replaced Using a Custom Coroutine Dispatcher fun runDemoViaCustomThreadPool(name: String) { val threadPool = Executors.newFixedThreadPool(2) val dispatcher = threadPool.asCoroutineDispatcher() runBlocking(dispatcher) { // ... } threadPool.shutdown() }
  • 72. These are functions that are supplied a suspend function/lambda and creates a coroutine Coroutine Builders Builder Description launch Returns a Job object representing the coroutine but is largely fire and forget. It is synchronised with another coroutine using join. async Returns a Deferred<T> object which is an extension of Job that includes a result. The result is acquired using await. runBlocking Runs a coroutine and blocks the current thread until it completes sequence Creates generators using a suspend function
  • 73. These suspending functions execute against a Coroutine Scope • They are extension methods of CoroutineScope Suspending Functions Builder Description delay Executes a non-blocking sleep yield Yields the thread in single thread disaptchers withContext Like runBlocking within a coroutine i.e. it suspends withTimeout Sets a time limit on execution of a function await, awaitAll Waits for one or multiple Deferred to complete and returns the result/s join, joinAll Waits for one or multiple jobs to complete
  • 74. class MyActivity : AppCompatActivity(), CoroutineScope { lateinit var job: Job override val coroutineContext: CoroutineContext get() = Dispatchers.Main + job override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) job = Job() } override fun onDestroy() { super.onDestroy() job.cancel() // Cancel job on activity destroy. After Destroy // all children jobs will be cancelled automatically } https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/ Android Activity
  • 75. class MyActivity : AppCompatActivity(), CoroutineScope { lateinit var job: Job override val coroutineContext: CoroutineContext get() = Dispatchers.Main + job override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) job = Job() } override fun onDestroy() { super.onDestroy() job.cancel() // Cancel job on activity destroy. After Destroy // all children jobs will be cancelled automatically } https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/ Android Activity
  • 76. fun loadDataFromUI() = launch { // this (Main) Dispatcher val ioData = async(Dispatchers.IO) { // IO Dispatcher // blocking I/O operation } // Work here will execute in parallel to IO // It will run on the Main thread val data = ioData.await() // Wait for result of I/O // Complete work in Main thread } Android Activity https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/
  • 77. fun voidPayment(tender: CheckTender) = launch(Dispatchers.Default) { when (tender.type) { CREDIT, MANUAL_CREDIT -> voidCreditPayment(tender) GIFT_CARD, MANUAL_GIFT_CARD -> voidGiftCardPayment(tender) else -> onVoidFailed() } } suspend fun voidCreditPayment(tender: CheckTender) { try { val voidPaymentResponse = voidService.voidPayment().await() when (voidPaymentResponse.result) { SUCCESS -> onCreditVoidSuccess(tender, voidPaymentResponse) else -> onCreditVoidFailed(tender, voidPaymentResponse) } } catch (throwable: Throwable) { onVoidFailed() } }
  • 78. Coroutines went stable in 1.3 Similar things exist in other languages • E.g. async await has been in C# since 2014, F# since 2012 • JavaScript, Python have very similar syntax to C# • Golang has goroutines & channels • They are all very useful at simplifying your code We now have a great solution for the JVM (and others) The Kotlin solution is built from primitives that open up flexibility Summary

Editor's Notes

  • #21: Easy to understand each section Simple Sequential Code
  • #23: Simply code Sequential
  • #24: Simply code Sequential
  • #37: You get to use all the stand
  • #43: If the pools are created then dispatch time is faster