Kotlin coroutines pre-emptive?

Just struck my mind: Are coroutines in Kotlin pre-emptive? In Go they are not as this makes the reduced context of the goroutine larger.

A coroutine can be thought of as an instance of suspendable computation , i.e. the one that can suspend at some points and later resume execution possibly on another thread. Coroutines calling each other (and passing data back and forth) can form the machinery for cooperative multitasking.

https://github.com/Kotlin/KEEP/blob/master/proposals/coroutines.md#use-cases

Yes, the point is do you need to yield the processor in some special cases to prevent the application from sitting as with languages that do not have pre-emptive multitasking such as Lua or goroutines in Go?

As a rule of thumb use a dedicated thread pool for long CPU-bound tasks, in such case the preemption load is negligible.
You can mix preemptive and cooperative multi-tasking using coroutine.

A coroutine will “own” the thread it is running on until it reaches a suspend point (delay(), await(), yield(), etc.). At that point the coroutine dispatcher might switch the thread to executing a different coroutine.

If you have some coroutines doing long-running work, and you are worried that other coroutines using the same dispatcher are being starved, you could call yield() to give up the thread to another coroutine. But I don’t think that’s a common case.

So you are saying coroutines are not preemptive.

That is a good point, but the question remains.

I never used yield in my software, coroutines are cooperative inside a thread pool (aka Dispatcher), but each thread is preemptive with each other threads.

Due to the intrinsic nature of coroutine implementation on JVM, yield is pretty ambiguous.

kotlinx.coroutines.yield is a function to suspend the current coroutine and to invoke the Dispatcher.
Thread.yield is a method to parking the current thread and invoke the OS scheduler.

A long-running coroutine on a proper Dispatcher does not shall invoke any kind of yield, it can consume the Dispatcher's time without issue, later the OS scheduler can park its thread to unpark any other Dispatcher's thread.
Understood these concepts, I hope that it is possible to find a convenient solution to your use case, and using the yield is only one of the alternatives.

If couroutines are not preemptive, there can be situations where the developer needs to yield the processor, see (runtime.Gosched() in Go causes a yield):


https://golang.org/src/runtime/proc_test.go

“It’s an interesting thing to discover that the goroutines may block each other in some situations like the sample code in this article.” (at the bottum of the article)

The question was whether coroutines in Kotlin are preemptive and you therefore do not need to call yield yourself in situations where required. As the Kotlin people themselves don’t answer, everything is just speculative.

No, coroutines are not preemptive, and will only give up the thread when they explicitly suspend/yield. That’s why you should try to avoid blocking calls in coroutines if they might be running in threads that are precious.

The thread that a coroutine is running in can still be preempted by other threads, of course, so it doesn’t hog a whole CPU.

BTW, I love the typo in the title of this thread. I keep interpreting it as, “Does the very subject of Kotlin coroutines lead to heated arguments before people even consider a particular forum post?” :wink:

As others have pointed out, coroutines are cooperative, not preemptive.

As has also been pointed out, on Kotlin/JVM the threads that coroutines run on are preemptive, so the CPU will never be starved by coroutines. I’m not familiar enough with threading on Kotlin/JS or Kotlin/Native to say how they work.

I think the only time you need to worry about yielding a coroutine is if you are using a dispatcher with a limited number of threads in its thread pool, and you have scheduled more coroutines than there are threads on that dispatcher, and you can’t wait for the currently running coroutines to finish before you let the queued coroutines do at least some work. But that should be a rare case.

1 Like

Yeah, I saw the typo some hours after creating the topic. Tried to fix, but then thought it looks funny and I can’t change the title anyway any more :joy:

Do note that the distance between preemptive and cooperative is less than it might appear. For example, Java thread safepoints are also a cooperative mechanism, but it behaves as preemptive for all practical purposes.

In the same manner the compiler could emit regular suspension checks and you could preempt a coroutine from the outside. It just doesn’t happen to do so because there’s no use case for that.