FlashspeedIfe
FlashspeedIfe

Reputation: 378

Why is Kotlin ignoring the delay(timeMillis: Long) function

The context

Following the Kotlin Coroutines basics guide at this point

using this code

fun coroutinesAreLightWeight()
{
    runBlocking {
        repeat(100_000) {
            launch {
                delay(1000L)
                print("$it, ")
            }
        }
    }
}

Issue

When I run the program on my computer it prints out all the digits in one go instead of waiting for 1 second to elapse before printing the next digit. This behaviour is the same when running the exact code as seen in the kotlin guide. It seems like the delay() function is being ignored

At first this block of code worked fine but then it stopped working as intended. I am using IntelliJ 2019.2.1 with kotlin version 1.3.50 and I have tried restarting the program but that didn't solve my problem.

Here is how the whole class looks like

class CoroutinesBasics
{
    fun ...

    fun ...

    fun coroutinesAreLightWeight()
    {
        runBlocking {
            repeat(100_000) {
                launch {
                    delay(1000L)
                    print("$it, ")
                }
            }
        }
    }
}

and the coroutinesAreLightWeight() function is called like this

fun main()
{
    CoroutineBasics().apply{
        ....
        ....
        coroutinesAreLightWeight()
    }
}

Can anyone point me to what is going on? Is this a Kotlin bug?

Kotlin dependencies

implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.0'

Upvotes: 0

Views: 480

Answers (2)

Alexey Soshin
Alexey Soshin

Reputation: 17731

I'll take another angle to answer this.
The example is given in a specific context. Namely, "coroutines are not like threads". The goal of the example is not to demonstrate how to print numbers with delays, but to demonstrate that coroutines, unlike threads, can be launched in thousands simultaneously. And that's exactly what this code is doing. It submits them all, then executes them all.

You may ask then, why they are all sequential? Shouldn't they run concurrently?
For that, let's print the thread name:

repeat(100_000) {
    launch {
       delay(100L)
       println("$it, ${Thread.currentThread().name}")
    }
}

You'll quickly see the reason: 99999, main

Since you're using runBlocking, all your coroutines are executed by a single thread.

We can change it, though:

runBlocking {
    repeat(100_000) {
        launch(Dispatchers.Default) {
            delay(100L)
            println("$it, ${Thread.currentThread().name}")
        }
    }
}

By using Dispatchers.Default, we're running our coroutines on a default thread pool. And then the results become much less predictable:

98483, DefaultDispatcher-worker-6
99898, DefaultDispatcher-worker-5
99855, DefaultDispatcher-worker-1
99706, DefaultDispatcher-worker-2

The default thread pool starts with 2 threads, and goes up to number of CPU cores by default. You can look at createDefaultDispatcher() for the actual implementation.

Regarding Thread.sleep(), you should know a few things:

  1. Never use Thread.sleep() inside coroutine
  2. Never use Thread.sleep() inside coroutine
  3. IntelliJ will even warn you to never use Thread.sleep() inside coroutine

Let's look at the following example to understand why:

repeat(100_000) {
   launch {
      Thread.sleep(100) 
      println("$it, ${Thread.currentThread().name}")
   }
}

You may assume what you're saying is "don't do anything in this block for 100ms".

But what you're actually saying is "don't do literally anything for 100ms".

Since launch will execute on context it got from runBlocking, and runBlocking is a single threaded context, you block executions of all coroutines.

Upvotes: 2

HSLM
HSLM

Reputation: 2022

This is the intended behavior as far as I know because coroutines are working simultaneously, so your code will only wait for 1 second for all coroutines that are currently working.

A good talk that I recommend about the coroutines is: KotlinConf 2017 - Introduction to Coroutines by Roman Elizarov

And it has the exact same example in the slides :)

if you want them to wait you should move the repeat to outside the 'runBlocking'

Upvotes: 0

Related Questions