Second Draft: Coroutines

Mai Lapyst mai at lapyst.by
Fri Jan 24 04:32:21 UTC 2025


On Sunday, 19 January 2025 at 18:46:23 UTC, Jin wrote:
> I see that you prefer not to notice the problems instead of 
> solving them. Good luck to you with this undertaking - you will 
> need it. But if this cancer of "modern" programming languages 
> ​​creeps into D, I’ll finally switch to some Go.

I think you have a misunderstanding (or mutliple here). Nobody 
here want's to take away threads or fibers from the language. And 
also: even threads and fibers have many of the same problems than 
stackless coroutines; the only difference really is the 
implementation and somewhat their usage.

> - [Low performance due to the inability to properly optimize 
> the code.] (https://page.hyoo.ru/#!=btunlj_fp1tum/ 
> View'btunlj_fp1tum'.Details=%D0%90%D1%81%D0%B8%D0%BD%D1%85%D1%80%D0%BE%D0%BD%D0%BD%D1%8B%D0%B9%20%D0%BA%D0%B5%D0%B9%D1%81)

Benchmarking is always only as good and usefull when used in the 
right environments. I can easily create benchmarks that also show 
how "slow" fibers are and how "fast" async is, as well as 
otherwise. Hell anyone could claim that just spawning more OS 
threads is "somehow" faster than any greenthread or async 
continuation if they just tweak their workload enough; because at 
the end of the day its exactly that whats the key to benchmarks: 
workload.

Any form of concurrency only really excells at what they are 
doing if used in an workload where it is key to do things 
concurrent / in parallel, which mainly is IO bound applications 
such as webservers. Any linear job, such as calculating a 
fibonacci number will always be slower when bloated with **ANY** 
form of concurrency. Just go ahead and try re-implementing it 
with fibers or OS Threads where every call to `fib(n)` spawns a 
new thread and joins it. I think anyone would agree that thats 
just insane waste of performance, which it rightfully is! Nobody 
in their right mind would try to calculate it in parallel because 
its still only a "simple" calculation.

Another thing is when you have to deal with Millions (!) of 
concurrent request on an webserver where there's no gurantee that 
any of the request resolve in linear time, or with other words, 
without waiting on another thing in some form, which is a stark 
contrast to a fibonacci calculation which always be resolveable 
without any further waiting once it's started. This is due to the 
purity of these two workloads: fibonacci is pure as it only ever 
require the inputs you give it directly. But 99.99% of any 
webrequest deals with some form of waiting: be it because you 
have an database you need to wait for, an cache adapter like 
redis or a file you need to read: IO is a large portion of time 
waiting for it. Thats why we have invented Fibers or async in the 
first place: spending the precious time we would wait otherwise 
doing actual work.

> - [The need to reinvent the stack as an AsyncContext.](https:// 
> github.com/tc39/proposal-async-context)

This need only arises from poorly used global variables / 
"impure" code, as the example you reference very good 
demonstrates; the async code captures all explicitly passed 
values to functions correctly. Only in the example where a 
"shared" variable (an global for all that matters here), is 
introduced, problems start to creep in. These problems also arise 
if one uses fibers btw, as globals are **always** a source of 
errors if not managed correctly. Thats one of the reasons D 
supports writing "pure" code: if you eliminate any implicit 
outside truth and only consider values explicitly passed via 
parameters or return values, your code magically gets way safer 
and also for a compiler to optimize for.

And btw, even threads and fibers have this context problem: 
because of that, we're invented thread-locals, or for the case of 
fibers, fiber locals. Just look and vibe.d; they build ontop of 
fibers and added a fiber-local storage because globals are 
inheritently a problem in physically **all** concurrent code, not 
only async/await stackless coroutines.

> But if this cancer of "modern" programming languages ​​creeps 
> into D, I’ll finally switch to some Go.

Thats funny that you mention go, as it has even some of the flaws 
you yourself mentioned; it has the same context problem with 
globals; it expects you (like many other languages) to use an 
mutex to protect it or use an type **literally** named 'Context'. 
Sure it has additionaly some race detection, but that gets you 
only so far. And your point on how you need an extra 
CancellationToken type: thats also true for **any** threading 
and/or fibers, and in go it's litterally one of the first thing 
you learn: waitgroups and context (again).

And I would ask you to keep this negativity out of these sort of 
discussions. Again, nobody will take away threads or fibers; all 
thats propsed here is that we get another tool in our toolbox. If 
you want to continue using fibers you're free to go. I also would 
mention that I wouldn't want fibers to be removed once stackless 
coroutines landed in D; D is an language for everyone, and as 
such should give as many tools to people as they need. There will 
always be some tool thats not used by everyone, but I see that as 
a win. Better have one tool to much than lacking it and resorting 
to weird hacks to get stuff working.


More information about the dip.development mailing list