Skip to content

Not work on single core CPU #288

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
JajaComp opened this issue Mar 15, 2018 · 16 comments
Closed

Not work on single core CPU #288

JajaComp opened this issue Mar 15, 2018 · 16 comments

Comments

@JajaComp
Copy link

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

@fvasco
Copy link
Contributor

fvasco commented Mar 15, 2018

The art of bug reporting

@JajaComp
Copy link
Author

JajaComp commented Mar 15, 2018

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

launch {
   println("hello")
}

@jcornaz
Copy link
Contributor

jcornaz commented Mar 15, 2018

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()
}

@JajaComp
Copy link
Author

JajaComp commented Mar 15, 2018

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

@jcornaz
Copy link
Contributor

jcornaz commented Mar 15, 2018

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

@JajaComp
Copy link
Author

JajaComp commented Mar 15, 2018

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

@elizarov
Copy link
Contributor

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

@JajaComp
Copy link
Author

JajaComp commented Mar 18, 2018

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

@JajaComp
Copy link
Author

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

@elizarov
Copy link
Contributor

@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.

@JajaComp
Copy link
Author

JajaComp commented Mar 20, 2018

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).

@elizarov
Copy link
Contributor

Any update?

@mangefox
Copy link

mangefox commented Jun 11, 2018

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.

@elizarov
Copy link
Contributor

elizarov commented Jun 15, 2018

@mangefox Can you share your test code, please?

@bradleydwyer
Copy link

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

@qwwdfsad
Copy link
Member

qwwdfsad commented Jul 3, 2018

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

elizarov added a commit that referenced this issue Jul 11, 2018
Also always construct private FJP pool if
kotlinx.coroutines.default.parallelism is explicitly specified.

Fixes #432, #288
elizarov added a commit that referenced this issue Jul 11, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants