Hacker News new | ask | show | jobs
by amelius 4099 days ago
Coroutines are essentially a form of cooperative multitasking. I'm not sure we should be using that in this day and age, especially considering that requests are not purely I/O bound in all cases, and could depend on actual computation.
1 comments

The fewer the trips to the kernel, the more work you can do in user-space, the fewer the sys-calls, the fewer the context switches, the better the throughput and performance.

Even if a request is completely CPU-bound, it’s a good idea to be fair to other requests accepted in the thread; that is, if a request should take 2 seconds of processing time, while others would take a few microseconds, they shouldn’t all wait until that one request is processed.

Instead, yielding back to the scheduler where appropriate, will give them a chance to complete in time proportional to the effort required to process them, not to the time required to handle long-running requests that stall processing of other coros.

Yielding will take CPU time, even when no yielding is necessary. And where to put these yields? In an inner-loop? Should all loops be rewritten to ensure a yield takes place at least every N instructions? Considering all this, I think a better approach would be to optimize the thread scheduler in the kernel, assuming it is as inefficient as you are suggesting.
In practice, you indeed yield often enough — there is no perfect formula I believe — so in loops or elsewhere where you are spending too much time doing one thing. You don’t need to do it perfectly, you just need to yield often enough to give other coros a fair chance at completion. Relying on the kernel is a bad idea; that’s where you lose on performance. Also, to do what you are suggestions would mean that you use many, many OS threads and the kernel somewhat manages them all in a pre-emptive fashion, and you don’t need to do it yourself; but that means you need to pay the context switching, memory footprint etc costs. It won’t scale and will be slow.
The memory footprint is there only to provide for stack-space. This makes me wonder, how do coros implement stacks? And don't they suffer effectively from the same problem?

Another point: what if your code calls a library function for which you don't have control over when it yields?