Hacker News new | past | comments | ask | show | jobs | submit login

You (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?




Wikipedia: 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.


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


It doesn't prevent it, but it can help with synchronization.

If you have two coroutines writing to the same variable, but they yield to each other, you know they won't ever both run at the same time.

You also know if you spawn multiple coroutines that they won't yield except where they call yield, so everything before and after the yield you know will be atomic.


> If you have two coroutines writing to the same variable, but they yield to each other, you know they won't ever both run at the same time.

But that won’t be parallel just concurrent, and in case of cooperative “threads”, you could have probably written it in a more readable single threaded way, as that’s pretty much just calling two functions back and forth.

Your second point also only works when you have a single thread of execution, otherwise concurrency will entail parallelism and all the usual problems will become apparent.


Threads still have the issue of synchronization and atomicity even when only concurrent and not parallel.

That is, assuming you had a single core CPU, with threads you'd still need to synchronize things when implementing concurrency. Coroutines have a more explicit synchronization from their natural ping/pong as you yield which could be said to tend to be safer in the average case.

I think you're maybe conflating something. If two things write to the same global variable for example, that can never be parallel, but it can be concurrent. With threads, the writes to the variables need to be guarded with some synchronization mechanisms, if you forget you'll have bugs.

With coroutines, they will be naturally synchronized by the yield points.

> you could have probably written it in a more readable single threaded way, as that’s pretty much just calling two functions back and forth

It's not just calling two functions back and forth, the coroutines retain state and continue where they yielded. Each time they yield they do not consume additional stack frames.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: