Tag: concurrency

Concurrent Coroutines – Concurrency is not Parallelism

Concurrent Coroutines – Concurrency is not Parallelism

On Kotlin Coroutines and how concurrency is different from parallelism

The official docs describe Kotlin Coroutines as a tool “for asynchronous programming and more”, especially are coroutines supposed to support us with “asynchronous or non-blocking programming”. What exactly does this mean? How is “asynchrony” related to the terms “concurrency” and “parallelism”, tags we hear about a lot in this context as well. In this article, we will see that coroutines are mostly concerned about concurrency and not primarily about parallelism. Coroutines provide sophisticated means which help us structure code to make it highly concurrently executable, also enabling parallelism, which isn’t the default behavior though. If you don’t understand the difference yet, don’t worry about it, it will get clearer throughout the article. Many people, I included, struggle to make use of these terms correctly. Let’s learn more about coroutines and how they relate to the discussed topics.

(You can find a general introduction to Kotlin coroutines in this article)

Asynchrony – A programming model

Asynchronous programming is a topic we’ve been reading and hearing about a lot in the last couple of years. It mainly refers to “the occurrence of events independent of the main program flow” and also “ways to deal with these events” (Wikipedia). One crucial aspect of asynchronous programming is the fact that asynchronously started actions do not immediately block the program and take place concurrently. When programming asynchronously, we often find ourselves triggering some subroutine that immediately returns to the caller to let the main program flow continue without waiting for the subroutine’s result. Once the result is needed, you may run into two scenarios: 1) the result has been fully processed and can just be requested or 2) You need to block your program until it is available. That is how futures or promises work. Another popular example of asynchrony is how reactive streams work like as described in the Reactive Manifesto:

Reactive Systems rely on asynchronous message-passing to establish a boundary between components that ensures loose coupling, isolation and location transparency. […] Non-blocking communication allows recipients to only consume resources while active, leading to less system overhead.

Altogether, we can describe asynchrony, defined in the domain of software engineering, as a programming model that enables non-blocking and concurrent programming. We dispatch tasks to let our program continue doing something else until we receive a signal that the results are available. The following image illustrated this:

We want to continue reading a book and therefore let a machine do the washing for us.

Disclaimer: I took this and also the two following images from this Quora post which also describes the discussed terms.

Concurrency – It’s about structure

After we learned what asynchrony refers to, let’s see what concurrency is. Concurrency is not, as many people mistakenly believe, about running things “in parallel” or “at the same time”. Rob Pike, a Google engineer, best known for his work on Go, describes concurrency as a “composition of independently executing tasks” and he emphasizes that concurrency really is about structuring a program. That means that a concurrent program handles multiple tasks being in progress at the same time but not necessarily being executed simultaneously. The work on all tasks may be interleaved in some arbitrary order, as nicely illustrated in this little image:

Concurrency is not parallelism. It tries to break down tasks which we don’t necessarily need to execute at the same time. Its primary goal is structure, not parallelism.

Parallelism – It’s about execution

Parallelism, often mistakenly used synonymously for concurrency, is about the simultaneous execution of multiple things. If concurrency is about structure, then parallelism is about the execution of multiple tasks. We can say that concurrency makes the use of parallelism easier, but it is not even a prerequisite since we can have parallelism without concurrency.

Conclusively, as Rob Pike describes it: “Concurrency is about dealing with lots of things at once. Parallelism is about doing lots of things at once”. You can watch his talk “Concurrency is not Parallelism” on YouTube.

Coroutines in terms of concurrency and parallelism

Coroutines are about concurrency first of all. They provide great tools that let us break down tasks into various chunks which are not executed simultaneously by default. A simple example illustrating this is part of the Kotlin coroutines documentation:


fun main() = runBlocking<Unit> { val time = measureTimeMillis { val one = async { doSomethingUsefulOne() } val two = async { doSomethingUsefulTwo() } println("The answer is ${one.await() + two.await()}") } println("Completed in $time ms") } suspend fun doSomethingUsefulOne(): Int { delay(1000L) return 13 } suspend fun doSomethingUsefulTwo(): Int { delay(1000L) return 29 }

The example terminates in roughly 1000 milliseconds since both “somethingUseful” tasks take about 1 second each and we execute them asynchronously with the help of the async coroutine builder. Both tasks just use a simple non-blocking delay to simulate some reasonably long-running action. Let’s see if the framework executes these tasks truly simultaneously. Therefore we add some log statements that tell us the threads the actions run on:

[main] DEBUG logger - in runBlocking
[main] DEBUG logger - in doSomethingUsefulOne
[main] DEBUG logger - in doSomethingUsefulTwo

Since we use runBlocking from the main thread, it also runs on this one. The async builders do not specify a separate CoroutineScope or CoroutineContext and therefore also inherently run on main.
We have two tasks run on the same thread, and they finish after a 1-second delay. That is possible since delay only suspends the coroutine and does not block main. The example is, as correctly described, an example of concurrency, not utilizing parallelism. Let’s change the functions to something that really takes its time and see what happens.

Parallel Coroutines

Instead of just delaying the coroutines, we let the functions doSomethingUseful calculate the next probable prime based on a randomly generated BigInteger which happens to be a fairly expensive task (since this calculation is based on a random it will not run in deterministic time):

fun doSomethingUsefulOne(): BigInteger {
    log.debug("in doSomethingUsefulOne")
    return BigInteger(1500, Random()).nextProbablePrime()
}

Note that the suspend keyword is not necessary anymore and would actually be misleading. The function does not make use of other suspending functions and blocks the calling thread for the needed time. Running the code results in the following logs:

22:22:04.716 [main] DEBUG logger - in runBlocking
22:22:04.749 [main] DEBUG logger - in doSomethingUsefulOne
22:22:05.595 [main] DEBUG logger - Prime calculation took 844 ms
22:22:05.602 [main] DEBUG logger - in doSomethingUsefulOne
22:22:08.241 [main] DEBUG logger - Prime calculation took 2638 ms
Completed in 3520 ms

As we can easily see, the tasks still run concurrently as in with async coroutines but don’t execute at the same time anymore. The overall runtime is the sum of both sub-calculations (roughly). After changing the suspending code to blocking code, the result changes and we don’t win any time while execution anymore.


Note on the example

Let me note that I find the example provided in the documentation slightly misleading as it concludes with “This is twice as fast, because we have concurrent execution of two coroutines” after applying async coroutine builders to the previously sequentially executed code. It only is “twice as fast” since the concurrently executed coroutines just delay in a non-blocking way. The example gives the impression that we get “parallelism” for free although it’s only meant to demonstrate asynchronous programming as I see it.


Now how can we make coroutines run in parallel? To fix our prime example from above, we need to dispatch these tasks on some worker threads to not block the main thread anymore. We have a few possibilities to make this work.

Making coroutines run in parallel

1. Run in GlobalScope

We can spawn a coroutine in the GlobalScope. That means that the coroutine is not bound to any Job and only limited by the lifetime of the whole application. That is the behavior we know from spawning new threads. It’s hard to keep track of global coroutines, and the whole approach seems naive and error-prone. Nonetheless, running in this global scope dispatches a coroutine onto Dispatchers.Default, a shared thread pool managed by the kotlinx.coroutines library. By default, the maximal number of threads used by this dispatcher is equal to the number of available CPU cores, but is at least two.

Applying this approach to our example is simple. Instead of running async in the scope of runBlocking, i.e., on the main thread, we spawn them in GlobalScope:

val time = measureTimeMillis {
    val one = GlobalScope.async { doSomethingUsefulOne() }
    val two = GlobalScope.async { doSomethingUsefulTwo() }
}

The output verifies that we now run in roughly max(time(calc1), time(calc2)):

22:42:19.375 [main] DEBUG logger - in runBlocking
22:42:19.393 [DefaultDispatcher-worker-1] DEBUG logger - in doSomethingUsefulOne
22:42:19.408 [DefaultDispatcher-worker-4] DEBUG logger - in doSomethingUsefulOne
22:42:22.640 [DefaultDispatcher-worker-1] DEBUG logger - Prime calculation took 3245 ms
22:42:23.330 [DefaultDispatcher-worker-4] DEBUG logger - Prime calculation took 3922 ms
Completed in 3950 ms

We successfully applied parallelism to our concurrent example. As I said though, this fix is naive and can be improved further.

2. Specify a coroutine dispatcher

Instead of spawning async in the GlobalScope, we can still let them run in the scope of, i.e., as a child of, runBlocking. To get the same result, we explicitly set a coroutine dispatcher now:

val time = measureTimeMillis {
    val one = async(Dispatchers.Default) { doSomethingUsefulOne() }
    val two = async(Dispatchers.Default) { doSomethingUsefulTwo() }
    println("The answer is ${one.await() + two.await()}")
}

This adjustment leads to the same result as before while not losing the child-parent structure we want. We can still do better though. Wouldn’t it be most desirable to have real suspending functions again? Instead of taking care of not blocking the main thread while executing blocking functions, it would be best only to call suspending functions that don’t block the caller.

3. Make blocking function suspending

We can use withContext which “immediately applies dispatcher from the new context, shifting execution of the block into the different thread inside the block, and back when it completes”:

suspend fun doSomethingUsefulOne(): BigInteger = withContext(Dispatchers.Default) {
    executeAndMeasureTimeMillis {
        log.debug("in doSomethingUsefulOne")
        BigInteger(1500, Random()).nextProbablePrime()
    }
}.also {
    log.debug("Prime calculation took ${it.second} ms")
}.first

With this approach, we confine the execution of dispatched tasks to the prime calculation inside the suspending function. The output nicely demonstrates that only the actual prime calculation happens on a different thread while everything else stays on main. When has multi-threading ever been that easy? I really like this solution the most.

(The function executeAndMeasureTimeMillis is a custom one that measures execution time and returns a pair of result and execution time)

23:00:20.591 [main] DEBUG logger - in runBlocking
23:00:20.648 [DefaultDispatcher-worker-1] DEBUG logger - in doSomethingUsefulOne
23:00:20.714 [DefaultDispatcher-worker-2] DEBUG logger - in doSomethingUsefulOne
23:00:21.132 [main] DEBUG logger - Prime calculation took 413 ms
23:00:23.971 [main] DEBUG logger - Prime calculation took 3322 ms
Completed in 3371 ms

Caution: We use Concurrency and Parallelism interchangeably although we should not

As already mentioned in the introductory part of this article, we often use the terms parallelism and concurrency as synonyms of each other. I want to show you that even the Kotlin documentation does not clearly differentiate between both terms. The section on “Shared mutable state and concurrency” (as of 11/5/2018, may be changed in future) introduces with:

Coroutines can be executed concurrently using a multi-threaded dispatcher like the Dispatchers.Default. It presents all the usual concurrency problems. The main problem being synchronization of access to shared mutable state. Some solutions to this problem in the land of coroutines are similar to the solutions in the multi-threaded world, but others are unique.

This sentence should really read “Coroutines can be executed in parallel using multi-threaded dispatchers like Dispatchers.Default…”

Conclusion

It’s important to know the difference between concurrency and parallelism. We learned that concurrency is mainly about dealing with many things at once while parallelism is about executing many things at once. Coroutines provide sophisticated tools to enable concurrency but don’t give us parallelism for free. In some situations, it will be necessary to dispatch blocking code onto some worker threads to let the main program flow continue. Please remember that we mostly need parallelism for CPU intensive and performance critical tasks. In most scenarios, it might be just fine to don’t worry about parallelism and be happy about the fantastic concurrency we get from coroutines.

Lastly, let me say Thank you to Roman Elizarov who discussed these topics with me before I wrote the article. 🙏🏼

Please follow and like this Blog 🙂

Simon is a software engineer based in Germany with 7 years of experience writing code for the JVM and also with JavaScript. He’s very passionate about learning new things as often as possible and a self-appointed Kotlin enthusiast.

Kotlin Coroutines Guide – Concurrent Programming in Kotlin

Kotlin Coroutines Guide – Concurrent Programming in Kotlin

updated 10/29/2018

Introduction and Motivation

In this article, you will learn about Kotlin Coroutines: What they are, what they look like, and how they work. The demonstrated code examples were tested with Kotlin 1.3.0 and kotlinx.coroutines 1.0.0.
Kotlin coroutines are one of the “bigger features” as indicated by the following quote, taken from JetBrains’ blog:

We all know that blocking is bad under a high load, that polling is a no-go, and the world is becoming more and more push-based and asynchronous. Many languages (starting with C# in 2012) support asynchronous programming through dedicated language constructs such as async/await keywords. In Kotlin, we generalized this concept so that libraries can define their versions of such constructs, and async is not a keyword, but merely a function.
This design allows the integration of different asynchronous APIs: futures/promises, callback-passing, etc. It is also general enough to express lazy generators (yield) and cover some other use cases.

The Kotlin team introduced coroutines to provide simple means for concurrent programming. Probably the vast majority of us already worked with some thread-based concurrency tool, e.g., Java’s concurrency API. I have worked with concurrent Java code quite a lot and mostly agree on the API’s maturity.

Java Concurrency vs. Kotlin Coroutines

If you still catch yourself struggling with threading and concurrency in Java, I can recommend the book Java Concurrency in Practice to you.

Although Java’s concurrency tooling is well-engineered, it’s often difficult to utilize and fairly tedious to use. Another problem is that Java doesn’t directly encourage non-blocking programming. You often find yourself starting threads without having in mind that they’re costly and introduce blocking computations quickly (due to locks, sleeps, waits, etc.). Applying non-blocking patterns alternatively is really hard and error-prone.

Kotlin Coroutines, on the other hand, are intended to be a lot easier and look like sequential code by hiding most of the complicated stuff from the developers. They provide a way to run asynchronous code without having to block threads, which offers new possibilities for applications. Instead of blocking threads, computations are being suspended.
Many sources describe coroutines as “light-weight threads”; they are not a thread as we know them from, e.g., Java though. Compared to threads, coroutines are mostly very cheap in their creation, and the overhead that naturally comes with threads isn’t around. One reason is that they’re not directly mapped to native threads. As you will see, coroutines are executed in thread pools that are mainly managed by the library.
Another critical difference is “limitation”: Threads are very limited because they rely on available native threads, coroutines on the other side are almost free, and thousands can be started at once (although this depends on what they compute).

Concurrent Programming Style

Different types of asynchronous/concurrent programming styles exist in various languages, for instance:
* Callback-based (JavaScript)
* Future/Promise-based (Java, JavaScript)
* Async/Await-based (C#) and more

All these concepts can be implemented with coroutines since Kotlin doesn’t dictate any of these directly.
As one additional benefit, as opposed to, for instance, callback-based programming, coroutines promote a sequential kind of asynchronous programming: Although your coroutines may execute multiple parallel computations, your code can still look sequential, just as we like it.

The Concept of Kotlin Coroutines

The term and concept “Coroutine” is anything but new. According to the Wikipedia article, it was created in 1958 already. Many modern programming languages provide native support: C#, Go, Python, Ruby, etc. The implementation of coroutines, also in Kotlin, is often based on so-called “Continuations”, which are “an abstract representation of the control state of a computer program”. We’ll learn a bit more about this in a later chapter of this article.

Getting Started with Coroutines

To set up a project with Kotlin coroutines, please use this step by step reference or simply check out my examples repository on GitHub and use it as a template.

Kotlin Coroutines Ingredients

As already hinted, the Kotlin coroutine library provides an understandable high-level API that lets us start quickly. One new modifier we need to learn is suspend, which is used to mark a method as “suspending”.
We’ll have a look at some easy examples using APIs from kotlinx.coroutines in the next section. But first, let’s learn what a suspending function is.

Suspending Functions

Coroutines rely on the suspend keyword, which is a modifier used to mark functions as “suspending”, i.e., that calls to such functions may suspend at any point. We can only call these functions from coroutines or other suspending functions.

suspend fun myMethod(p: String): Boolean {
    //...
}

As we can see in the example above, suspending functions look like a regular function with an additional modifier added to it. Keep in mind that invoking such a function from a normal function will lead to compilation errors.

We can think of a coroutine as a sequence of calls to regular as well as suspending functions. This sequence optionally provides a result at the end of its execution.

Hands-On

Let’s finally see some concrete coroutines in action. In a first example, the basics will be shown:

fun main(args: Array<String>) = runBlocking { //(1)
    val job = GlobalScope.launch { //(2)
        val result = suspendingFunction() //(3)
        print("$result")
    }
    print("The result: ")
    job.join() //(4)
}
// prints "The result: 5"

In this example, you can see two new functions, (1) runBlocking and (2) launch, both of which are examples of coroutine builders. We can utilize various builders, and they all start a coroutine with different purposes: launch (fire and forget, can also be canceled), async (returns promise), runBlocking (blocks thread) and more. We can start coroutines in different scopes. In this example, the GlobalScope is used to spawn a launch coroutine that is as a result of this limited to the application lifecycle itself. This approach is fine for most examples we will see in this article, but it will most probably not be sufficient for your real-life applications. Following the concept of “structured concurrency”, we need to confine coroutines to different scopes to make them maintainable and manageable. Read about the concept of CoroutineScope here.

Let’s observe what this code does: The inner coroutine started by (2) launch does the actual work: we call a (3) suspending function and then the coroutine prints its result. The main thread, after starting the coroutine, prints a String before the coroutine finishes.
Coroutines started by launch return a Job immediately, which we can use to cancel the computation or await its completion with (4) join() as we see here. Since calling join() may suspend, we need to wrap this call into another coroutine, which is why we use runBlocking as a wrapper. This concrete coroutine builder (1)is designed to bridge regular blocking code to suspending functions, and we can use it in main functions and tests” (Quoted API). If we removed the joining of the job, the program would stop before the coroutine can print the result.

It’s possible to spawn launch in the scope of the outer runBlocking coroutine directly. To do so, we change GlobalScope.launch to just launch. As a result, we can now also remove the explicit join since runBlocking won’t complete before all of its child coroutines finish. This example again is a demonstration of structured concurrency, a principle we want to observe in more detail next.

Structured Concurrency

As mentioned in the previous section, we can structure our coroutines in a way that they are more manageable by creating a certain hierarchy between them. Imagine you work with a user interface which, for any reason, we need to terminate at a certain point due to some event. If we started coroutines which handle certain tasks in that UI, these also should be terminated when the main task stops. With coroutines, it’s vital to keep in mind that each coroutine can run in a different scope. We often want to group multiple coroutines by a shared scope so that they can, for instance, be canceled altogether easily. Let’s re-use the basic coroutine composition we saw in the first code snippet above but now with launch running in the scope of runBlocking and slightly different tasks:

fun main(args: Array<String>) {
    runBlocking {
        launch {
            delay(500)
            println("Hello from launch")
        }
        println("Hello from runBlocking after launch")
    }
    println("finished runBlocking")
}

This code prints the following output:

Hello from runBlocking after launch
Hello from launch
finished runBlocking

This output tells us that runBlocking does not complete before its child coroutine started by launch finishes its work. Further, we can use this structure to easily delegate the cancellation on a certain coroutine down to its child coroutines:


fun main(args: Array<String>) { runBlocking { val outerLaunch = launch { launch { while (true) { delay(300) println("Hello from first inner launch") } } launch { while (true) { delay(300) println("Hello from second inner launch") } } } println("Hello from runBlocking after outer launch") delay(800) outerLaunch.cancel() } println("finished runBlocking") }

This code prints something like this:

Hello from runBlocking after outer launch
Hello from first inner launch
Hello from second inner launch
Hello from first inner launch
Hello from second inner launch
finished runBlocking

In this example, we can see a launch that creates an outer coroutine that then again launches two inner coroutines, all in the same scope. We cancel the outer coroutine which then delegates its cancelation to the inner coroutines, and nothing keeps running afterward. This approach also handles errors correctly since an exception happening in an arbitrary child coroutine will make all coroutines in its scope stop.

Custom Scope

Last but not least, we want to go a step further and create our very own CoroutineScope. In the last examples, we simply used the scope given by runBlocking, which we only did for convenience. In real-life applications, it’s necessary to create custom scopes to manage one’s coroutines effectively. The API comes with a simple builder for this: coroutineScope. It’s documentation states:

Creates new [CoroutineScope] and calls the specified suspend block with this scope. The provided scope inherits its [coroutineContext][CoroutineScope.coroutineContext] from the outer scope, but overrides context’s [Job]. This function is designed for a parallel decomposition of work. When any child coroutine in this scope fails, this scope fails, and all the rest of the children are canceled (for a different behavior see [supervisorScope]).

fun main(args: Array<String>) = runBlocking {
    coroutineScope {
        val outerLaunch = launch {
            launch {
                while (true) {
                    delay(300)
                    println("Hello from first inner launch")
                }
            }
            launch {
                while (true) {
                    delay(300)
                    println("Hello from second inner launch")
                }
            }
        }

        println("Hello from runBlocking after outer launch")
        delay(800)
        outerLaunch.cancel()
    }
    println("finished coroutineScope")
}

The code looks pretty similar to what we saw earlier, but now we run our coroutines in a custom scope. For further reference, please read this post on structured concurrency with coroutines.

Going deeper

A more vivid example is the following: Imagine, you have to send an email from your application. Requesting the recipient address and rendering the message body are two costly tasks, which are independent of each other though. Being smart and using Kotlin, you want to make use of coroutines, performing both tasks in parallel.
This is shown here:

suspend fun sendEmail(r: String, msg: String): Boolean { //(6)
    delay(2000)
    println("Sent '$msg' to $r")
    return true
}

suspend fun getReceiverAddressFromDatabase(): String { //(4)
    delay(1000)
    return "coroutine@kotlin.org"
}

suspend fun sendEmailSuspending(): Boolean {
    val msg = GlobalScope.async { //(3)
        delay(500)
        "The message content"
    }
    val recipient = GlobalScope.async { 
        getReceiverAddressFromDatabase() //(5)
    } 
    println("Waiting for email data")
    val sendStatus = GlobalScope.async {
        sendEmail(recipient.await(), msg.await()) //(7)
    }
    return sendStatus.await() //(8)
}

fun main(args: Array<String>) = runBlocking { //(1)
    val job = GlobalScope.launch {
        sendEmailSuspending() //(2)
        println("Email sent successfully.")
    }
    job.join() //(9)
    println("Finished")
}

First, like already seen in the previous example, we use a (1) launch builder inside a runBlocking builder so that we can (9) wait for the coroutine’s completion. This structure isn’t new, and neither is (2) calling a suspending function (sendEmailSuspending).
This method uses an (3) inner coroutine for getting the message content and (4) another suspend method getReceiverAddressFromDatabase for getting the address. We execute both tasks in a separate coroutine built with (5) async. Note, that the calls to delay represent a non-blocking, coroutine-suspending, alternative to Thread.sleep, which we use for mocking expensive computations here.

The async Coroutine Builder

The async builder is simple and easy in its conception. As we know from many other languages, it returns a promise, which is of type Deferred in Kotlin. By the way, promise, future, deferred or delay are often used interchangeably for describing the same concept: The async method promises to compute a value which we can wait for or request at any time.

We can observe the “waiting” on Kotlin’s Deferred object in (7) where the suspending function (6) is called with the results of both prior computations. The method await() is called on instances of Deferred which suspends until the results become available. The call to sendEmail is also part of an async builder. Finally, we await its completion in (8) before returning its result.

Shared Mutable State

It’s possible that you already had concerns about synchronization between coroutines while reading the article as I didn’t mention anything about it yet. I, at least, had this concern because coroutines can work on shared state concurrently. It’s quite evident that being aware of this is just as important as we know it from other languages like Java. We can make use of acquainted strategies like thread-safe data structures, confining execution to a single thread or using locks.
Besides the common patterns, Kotlin coroutines encourage the concept of “share by communication” (see QA).

Concretely, an “actor” can be used to represent a state that we safely share between coroutines. Coroutines can use actors to send and receive messages through them. Let’s see how this works:

Actors

sealed class CounterMsg {
    object IncCounter : CounterMsg() // one-way message to increment counter
    class GetCounter(val response: SendChannel<Int>) : CounterMsg() // a request with channel for reply.
}

fun counterActor() = GlobalScope.actor<CounterMsg> { //(1)
    var counter = 0 //(9) </b>actor state, not shared
    for (msg in channel) { // handle incoming messages
        when (msg) {
            is CounterMsg.IncCounter -> counter++ //(4)
            is CounterMsg.GetCounter -> msg.response.send(counter) //(3)
        }
    }
}

suspend fun getCurrentCount(counter: SendChannel<CounterMsg>): Int { //(8)
    val response = Channel<Int>() //(2)
    counter.send(CounterMsg.GetCounter(response))
    val receive = response.receive()
    println("Counter = $receive")
    return receive
}

fun main(args: Array<String>) = runBlocking<Unit> {
    val counter = counterActor()

    GlobalScope.launch { //(5)
            while(getCurrentCount(counter) < 100){
                delay(100)
                println("sending IncCounter message")
                counter.send(CounterMsg.IncCounter) //(7)
            }
        }

    GlobalScope.launch { //(6)
        while ( getCurrentCount(counter) < 100) {
            delay(200)
        }
    }.join()
    counter.close() // shutdown the actor
}

This example shows the usage of an (1) Actor, which is a coroutine itself working on any context. The actor is holding the (9) relevant state of this sample application, which is the mutable counter variable. Another important feature we haven’t considered so far is a (2) Channel.

Channels

Channels provide a way to transfer a stream of values, similar to what we know as BlockingQueue (enables producer-consumer pattern) in Java but without any blocking methods. Instead, send and receive are suspending functions used for providing and consuming objects from the channel, implemented with a FIFO strategy.

An actor is by default connected to such channels, which other coroutines (7) can use to communicate with other coroutines. In the example, the actor iterates over the stream of messages from its channel (for works with suspending calls) handling them according to their type: (4) IncCounter messages make the actor change its state by incrementing the counter while (3) GetCounter makes the actor return its counter state by sending an independent message to the GetCounter‘s SendChannel.
The first coroutine (5) in main launches a task that sends (7) IncCounter messages to the actor as long as the counter is less than 100. The second (6) one waits until the counter reaches 100. Both coroutines make use of the suspending function (8) getCurrentCounter, which sends a GetCounter message to the actor and suspends by waiting for receive to return.

As we can see, the entire mutable state is confined to the specific actor coroutine, which solves the problem of shared mutable state and follows the principle of share by communication.

More Features and Examples

You can find more examples and great documentation in these documents.

How it works – Implementation of Kotlin Coroutines

Coroutines do not rely on features of the operating system or the JVM. Instead, the compiler transforms coroutines and suspend functions and produces a state machine which is capable of handling suspensions in general and passing around suspending coroutines keeping their state. The concept of Continuations enables this feature. Continuations are being added to every suspending function as an additional parameter by the compiler. This technique is called “Continuation-passing style”.

Let’s see how the following function looks like after adding a continuation to it:

suspend fun sampleSuspendFun(x: Int): Int {
    delay(2000)
    return x * x
}

The compiler modifies this function to something like this:

public static final Object sampleSuspendFun(int x, @NotNull Continuation var1)

It adds another parameter, the Continuation, to it. Now, if we call this function from a coroutine, the compiler will pass the code that occurs after the sampleSuspendFun function call as a continuation. After the sampleSuspendFun completes its work, it will trigger the continuation. That’s just what we know from a callback-based programming model already but hidden by the compiler. To be honest, this is just a simplified explanation. You can learn more about the details here.

QA with Roman Elizarov (JetBrains)

I had the chance to formulate a few questions to Roman Elizarov who works for JetBrains and who’s highly responsible for Kotlin coroutines. Read what he said:

Q: When am I supposed to use coroutines and are there any use cases that still require explicit threading?

A: Rule of thumb by Roman:
Coroutines are for asynchronous tasks that wait for something most of the time. Threads are for CPU-intensive tasks.

Q: The phrase “light-weight thread” sounds kind of inappropriate to me as it obscures the fact that coroutines rely on threads and that the library executed them in a pool of threads.* I’d prefer something more simple, such as a “task” that’s being executed, stopped, etc. Why did you decide to describe them like threads anyway?

A: Roman answered, that the phrase “light-weight threads” is rather superficial, and that “coroutines are in many ways like threads from user’s standpoint.”

Q: If coroutines are similar to threads, there must be the necessity of synchronizing shared state between different coroutines, right? *

A: Roman told me, that we can still use known patterns of synchronization, but it is highly recommended to not have any mutable shared state at all when we use coroutines. Instead, coroutines encourage the “share by communication” style.

Conclusion

As opposed to Java, Kotlin encourages an entirely different style of concurrent programming, which is non-blocking and naturally doesn’t make us start vast amounts of native threads.
Writing concurrent Java code often implies starting too many threads or forgetting about proper thread pool management. This carelessness though introduces a huge overhead that results in slowed down execution. Coroutines, as an alternative, are said to be “light-weight threads”, which describes the fact that they’re not mapped to native threads and therefore don’t drag along all the risks and problems we usually have to deal with (deadlocks, starvation, e.g.). As we’ve seen, with coroutines, we normally don’t have to worry about blocking threads. Moreover, synchronization is more straightforward and ideally not even necessary as long as we pursue the “share by communication” principle.

Coroutines also enable us to work with several different kinds of concurrent programming. Many are already available, and it’s possible to add others.
Java developers, in particular, will most likely favor the async/await style which looks similar to what they already know from working with futures. It’s not just a comparable replacement but a significant improvement to what we know already.
Concurrent Java code comes with a lot of checked exceptions, defensive locking strategies and general boilerplate code. All of this can be improved by coroutines, which allow concurrent code to look sequential, be manageable and easily readable.

Perspective

Coroutines will finally be made generally available with Kotlin 1.3. The Kotlin team will remove the “experimental” nature of it, and coroutines will remain in a stable state.

Today (29/10/2018), Kotlin 1.3 has been released which includes a stable version of coroutines 🙂

Please don’t hesitate to get in touch, feedback’s always appreciated 🙂 Also if you like, have a look at my Twitter and follow if you’re interested in more Kotlin stuff. Thanks a lot. If you want to read more about Kotlin’s beautiful features I highly recommend the book Kotlin in Action and my other articles to you.

Simon

Please follow and like this Blog 🙂

Simon is a software engineer based in Germany with 7 years of experience writing code for the JVM and also with JavaScript. He’s very passionate about learning new things as often as possible and a self-appointed Kotlin enthusiast.