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

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
Most helpful comment