Kotlin Coroutines – Asynchronicity for Procedural Thinkers

January 14, 2020

Coroutines are computer program components that generalize subroutines for non-preemptive multitasking, by allowing execution to be suspended and resumed. (source: wikipedia)

With that we could close the blog post, everything’s said. We, however, want to dive a bit deeper into what coroutines are, why it is helpful to use them and how they make writing asynchronous code understandable and maintainable. We also want to discover the still pretty fresh support for coroutines in Kotlin.

Mind the Procedure

Development of asynchronous applications or services is like a symphonic orchestral performance where everyone plays on her/his own, but they still have to work together to build a single piece of music.

In contrast though, developers understand how their procedural code works, being executed almost line by line, but often have a hard time following asynchronous flows.

Gathering an understanding of how asynchronous code is executed is often tedious work, including drawing flow diagrams, and sometimes using a debugger, or even worse log messages.

The question though is, why exactly is an asynchronous code base so complicated to wrap our head around? And the answer is simple, the code flow of a unit of work is broken into pieces. Some may run in parallel, because they don’t have a dependency on each other, others might run sequential.

Looking at a simple example of procedural but sequential code, we can see that the code is executed line by line and while waiting for the response, we block the current execution.

So let’s imagine a method such as

  fun requestSomeValue(): String {
    sleep(5000)
    return “someValue”
  }

  println(“requesting value…”)
  var response = requestSomeValue()
  println(“value: ${response}”)
  println(“finished”);

To imitate some extremely slow network call we wait for 5 seconds before returning the value to the caller. In the case of a network call, we’d wait for the server to respond, obviously.

If requestSomeValue takes a while to be executed, the calling code block would have to wait until the response is retrieved. This will normally block an operating system thread which cannot be used otherwise.

The procedural flow of this code can be summarized as

  1. println: requesting value…
  2. sleep
  3. return
  4. println: value: someValue
  5. println: finished

I guess everyone is able to follow that flow and agrees. No questions asked.

Use async they said; Life will be great they said

If we look at it from the perspective of a more asynchronous design, it most often becomes harder to understand. The following example will use some JavaScript Promise inspired approach.

  fun requestSomeValue(): Promise<String> {
    return Promise.async { resolve ->
      sleep(5000)
      resolve(“someValue”)
    }
  }

  println(“requesting value…”)
  var promise = requestSomeValue()
  promise.then { response ->
    println(“value: ${response}”)
  }
  println(“finished”);

So now it becomes more complex to follow the code flow. The most obvious answer would be to see “finished” before our “someValue” println. This, however, is totally up to the implementation of the runtime to execute it. The runtime might be happy executing it in a sequential way. Remember JavaScript engines are all single threaded, at least the ones according to the specification.

What will happen most of the time though, we will see “finished” before “someValue”. The runtime will see the async call, starts executing it and stops execution on sleep for roughly the requested 5 seconds. It will then resume the code of the Promise and will resolve it. Resolving the Promise will eventually lead to executing the Promise.then callback.

But feel free to ignore looking into Promise implementations, they’re horrific since the detailed behavior is pretty complex. To get some feeling about the complexity inside, I rather recommend reading the Promises A+ specification.

Oh and before I forget, there are millions of other ways to build an example like this in an async way; callback (hell), promises, threads with mutexes are just a few to name here. And believe me, none of those are great. They get the job done, but that’s about it.

Cooperative Routines

So a great solution would bring the benefits of sequential programming and asynchronicity together, to build a solid foundation for developers without 10 years of experience in async application design. And don’t get me wrong, even after more than 10 years, I still wouldn’t consider myself an expert ?

Coming back to the initial quote from Wikipedia we can paraphrase it as “Coroutines are subroutines for asynchronous applications by allowing execution of parts of the program to be suspended and resumed.

Let me guess, still doesn’t make any more sense, does it? No worries, an example makes it easier.

  fun suspend requestSomeValue(): String {
    sleep(5000)
    return “someValue”
  }

  runBlocking {
    println(“requesting value…”)
    var response = requestSomeValue()
    println(“value: ${response}”)
    println(“finished”);
  }

It does look almost like the first example, so what’s the big deal here? Well, the important magic is the suspend keyword in the function declaration and the runBlocking call.

What happens is, that the runBlocking tells the runtime, that we might want to suspend the execution of the code and let other code run while we’re waiting for something to happen. In our example, we will wait for 5 seconds. The interesting bit is though, our code still looks like sequential.

To describe our code flow, we can use the following list:

  1. println: requesting value…
  2. sleep

    1. suspend
    2. timeout
    3. resume
  3. return
  4. println: value: someValue
  5. println: finished

What we see is, that the runtime suspends the execution when we call sleep and sets a timeout to resume execution. Our code runs exactly as the first example and looks so similar, that it is hard to even consider it really different.

Power Generators

But that’s not all, Coroutines can do much much more. I want to present one other small example, for a feature or pattern I really like; Generators.

Everybody knows the problem of generating lists of values, but we might not know how many values we really need. Even though it is not that common, imagine writing code to generate an infinite number of values.

Normally we’d go ahead and write an endless loop, and at some point we might break out of it.

  var i = 0
  while(true) {
    i++
    println(“value: ${i}”)
  }

As good developers though, we love to write reusable code – and we all know that copy+paste is the wrong kind of code reuse!

With Coroutines we can build a generator, that indefinitely builds new values, until we stop requesting additional values. The interesting part, we generate them one by one, just like we did in the example before (which will never stop, as long as the number range is ok ?).

  val infiniteSequece = sequence {
    var i = 0
    while(true) {
      yield(i)
      i++
    }
  }

Guess what, execution of the above code is suspended at yield. We can ask the sequence to generate as many values as we like.

  val values = infiniteSequence.take(5).toList()

Everytime we ask for a new value, in the above code the take(5) will do that 5 times, we resume operation of the sequence generator, increment the value and yield again. Lazy for the win.

Kotlin, Instana and Coroutines

Anyways, I wanted to be one of the cool kids and end the blog post with an amazing example of what a microservice using Kotlin and Coroutines looks like in Instana. We support Kotlin for a while now, but just recently added Coroutines support.

The demo service, just has a single HTTP endpoint and calls another HTTP service inside a coroutine for better utilization of the OS threads.

What was a bummer for me (no cool fancy demo), is a pretty amazing situation for everyone else; it just works!

Nothing special had to be done, the screenshot looks just like any Java or Kotlin service. Even though for this blog post it’s sad to not have a cool, funky screenshot, I feel amazingly good that it just worked. ?

Anyway since I don’t want to keep us waiting any longer:


Kotlin Co-Routines being monitored with Instana showing up in the Dashboard
Figure 1: Kotlin Coroutines “Brewservice” in Instana: https://gist.github.com/noctarius/e4a7df234d10842993e169c69739d6be

If you want to try Kotlin, Coroutines, Microservices and Instana, sign up here for a https://www.instana.com/trial/ and see how easy and painless fully automatic monitoring of your services and infrastructure can be with Instana’s AutoTrace technology.

Start your FREE TRIAL today!

Automatic Application Performance Monitoring (APM) solutions for microservices, Instana has developed the automatic monitoring and AI-based analysis DevOps needs to manage the performance of modern applications. Instana is the only APM solution that automatically discovers, maps and visualizes microservice applications without continuous additional engineering. Customers using Instana achieve operational excellence and deliver better software faster. Visit https://www.instana.com to learn more.