4 ms·
They're not coroutines though. This is a little semantic, but a coroutine normally uses cooperative multitasking exclusively. Something like: coroutine fo
by didibus 5y ago
They're not coroutines though. This is a little semantic, but a coroutine normally uses cooperative multitasking exclusively.
Something like:
coroutine foo
while queue not full
put something in queue
when full
yield bar
coroutine bar
while queue not empty
take from queue
do something with what was taken
when empty
yield foo
Each time the coroutine yields, it removers it's state and execution resume another coroutine, and when execution is yield back it too resume from the yield point.
As I understand, in Java, they are not adding coroutines, but something that is a virtual thread, which is more like a green or lightweight thread. It means that it can be pre-emptively paused and resumed, it doesn't have to voluntarily yield. There is some scheduler that could decide when to execute which virtual thread and so on.
- Twisol 5y agoRight; Java's virtual threads are (*adjusts glasses*) preemptively-scheduled stackful continuations, meaning (1) that they execute in parallel and in cooperation with the OS' scheduler (*) (which automatically timeslices the CPU amongst threads), and (2) that each continuation is the full call stack at its yield site. The alternative for point 1 is cooperative scheduling (announcing explicitly when they yield), as you've described. The alternative for point 2 is "stackless" continuations, where the task yields by returning a callback describing the next step of the task -- or, equivalently, returning some data describing the state of the task, which the task's primary entry point can use to decide where to continue from. (For instance, imagine a function with a big `switch` statement that, when invoked, decides which case to jump into based on its argument, which the caller got from the return value of the last time it got invoked.) Either way, every step of the task constructs and then returns out of its call stack, which can be much more memory efficient, but is also more painful to model tasks in without help from the compiler/language. (*) Technically, the JVM could take on the role of scheduler as well; it could count the number of bytecode instructions executed, say, and pre-empt a task after some number. This is what Lua supports for some of its sandboxing capabilities. But I think that would be counter to Java's use of an OS thread pool to execute these virtual threads; its own scheduler would be interleaving somewhat unpredictably with the OS'. You'd want to do that if you have long-running jobs that do little I/O (so they hog an OS thread)... but then you'd probably rather put those jobs on actual background worker threads.
- wruza 5y agoYou (or a language) don’t have to yield-to another coroutine. You may resume and yield-from as in: coroutine producer forever while no full packet resume recv into buffer on eof return null yield (extract packet) coroutine consumer while packet = (resume producer) if packet is null break process packet which is more like a green or lightweight thread. It means that it can be pre-emptively paused and resumed, it doesn't have to voluntarily yield I’ve never heard of this meaning of coro/green/light distinction. Can you please point to some literature?
- didibus 5y agoWikipedia: https://en.m.wikipedia.org/wiki/Coroutine https://en.m.wikipedia.org/wiki/Coroutine In your example, it seems to still be cooperative, you simply yield to the scheduler which is itself a coroutine and will then decide what other coroutine to yield back too. Here's a naive coroutine scheduler : ArrayList coroutines; coroutine scheduler for i = 0;; i = i++ % coroutines.size() yield coroutines[i] It's still voluntary yielding though, preemptive would be that the scheduler can at any time interupt the task, but here it can't, it will still only be possible to schedule another task ounce a yield point voluntarily yields back to the scheduler. Actually, your example is simpler then that: (resume producer) is the same as: yield producer. And the yield with a return value is the same as: yield consumer. For the latter, the language probably allows yielding to the previous coroutine under the hood or like I said maybe it yields to a scheduler. I was also showing that you can even do something like yield to a scheduler which will then pick the next coroutine to resume, which makes it even more "thread like", but still cooperative. The coroutine's cooperative nature has an advantage, it naturally models coordination. With a preemptive scheme like Java virtual thread, you will still have to protect shared data and have ways to coordinate and synchronize like mutex, locks and all that.
- kaba0 5y ago> With a preemptive scheme like Java virtual thread, you will still have to protect shared data and have ways to coordinate and synchronize like mutex, locks and all that. As far as I know there is nothing preventing race conditions and dead/live locks in case of coroutines either, isn’t there? Like of course if you have 1 thread these issues won’t come up, but with true parallelism, this model in itself doesn’t protect anything.