Kotlinx.coroutines: Not work on single core CPU

Created on 15 Mar 2018  ·  16Comments  ·  Source: Kotlin/kotlinx.coroutines

Coroutines not work on single core CPU. For example - Moto 360 1st

waiting for clarification

Most helpful comment

The art of bug reporting

All 16 comments

The art of bug reporting

When I run the coretine on Moto 360 1gen nothing happens.
Coroutines version is 0.22.*

launch {
   println("hello")
}

launch fire and forget a coroutine which is like as a deamon thread.

You have to wait for the completion.

Example:

fun main(args: Array<String>) = runBlocking {
  val job = launch {
    println("hello")
  }

  job.join()
}

I run this actions in activity in methid onCreate().
On other watches my code worked perfect, but not on Moto.

Can you share a self-contained example which allows to reproduce the problem?

I just create new project with single activity.
Next i use this code:

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        setAmbientEnabled()
        Log.d("CORO", "main thread")
        launch {
            Log.d("CORO", "launch test")
        }
        runBlocking {
            Log.d("CORO", "runBlocking test")
        }

        thread {
            Log.d("CORO", "thread test")
        }

        async {
            Log.d("CORO", "async test")
        }
    }

And result is:

03-15 22:59:21.298 3536-3536/com.example.myapplication D/CORO: main thread
03-15 22:59:21.373 3536-3536/com.example.myapplication D/CORO: runBlocking test
03-15 22:59:21.385 3536-3550/com.example.myapplication D/CORO: thread test

without launch block

@JajaComp Do you observe it on the emulate or on the actual device? What Android version does it have?

I use real device. Is Moto 360 1gen. Android wear version is latest with 23 API.

@elizarov Я думаю проблема в том, что в данном устройстве одноядерный процессор. Пока нашел костыль и использую проверку на (Runtime.getRuntime().availableProcessors() > 1). Если возвращается единица, делаю через Thread, а если >1 то запускаю launch {}

@JajaComp If there is some kind of a problem on single-core CPUs, then it should be possible to imitate this problem in emulator of the single-core CPU.

I can't repeat this trouble on emulator with 1-core (I tested this). But 100% don't work on other Moto 360 1gen (Information from app statistic).

Any update?

Ran into the same issue on a provisioned virtual machine with one CPU. Tried spawning an infinite-loop queue-consumer in a coroutine and it worked on my machine but not the limited virtual one. Changing to a thread{ } worked however.

@mangefox Can you share your test code, please?

I just hit something possibly similar in a Kubernetes cluster on GKE. A pod with 1000m cpu requested (= 1 vCPU) has issues executing anything in an async coroutine. If I allocate 2000m it executes the coroutines without issue. The underlying host for the 1000m allocation had 2 vCPUs and the 2000m allocation had 4 vCPUs on the host.

It's the first time I've attempted to use coroutines so it wouldn't be surprising to me if I've done something a bit silly here. Like the original poster I only hit this after I executed the program somewhere other than my local dev machine (which has 4 cores).

The basic structure of the app is:

fun main(args: Array<String>) = runBlocking {
    async {
        for (sig in signalChannel) {
            if (sig == 0) {
                terminate = true
            }
        }
    }
    val blockTermination = async {
        while (!terminate) {
            delay(1000)
        }
        println("Goodbye, world!")
    }

    val application = Application()
    println("This println is executed")
    application.start()

    blockTermination.join()
}

In Application.start it fires off 4 of roughly the following:

fun example(): Deferred<Unit> {
    println("This println is executed")
    return async {
        println("This println is never executed")
        // wait on a channel for something to do OR // while(true) loop with a delay as above.
    }
}

Update: I thought I'd check that other difference, the 2 vCPU host vs the 4 vCPU host. It seems that the 1 vCPU allocation to the Kotlin app on the 2 vCPU host locks, but doesn't on the 4 vCPU host. So the summary on that is:

2 vCPU host. 1 vCPU allocation to Kotlin = locking
4 vCPU host. 1 vCPU allocation to Kotlin = working
4 vCPU host. 2 vCPU allocation to Kotlin = working

Hi @bradleydwyer
Unfortunately, I still cannot reproduce it.
Could you please provide a self-contained example which is verified to hang?
I suspect either concurrency bug or problems with Runtime.getRuntime().availableProcessors() which is known to not working properly in a containerized environment.

Also note that terminate should be marked as @Volatile and in general it's not recommended to communicate via shared variables. Joins and invokeOnCompletion are less error-prone and CPU-intensive

Was this page helpful?
0 / 5 - 0 ratings