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