3 ms·
> Rust's approach to async is the best I've seen so far in any language I'm not a Rust programmer but have used async/await in both Python and C#. I've also w
by spinningslate 3y ago
> Rust's approach to async is the best I've seen so far in any language
I'm not a Rust programmer but have used async/await in both Python and C#. I've also written concurrent code in Erlang. I'd choose the Erlang approach over async/await every time. One concurrency primitive - the process - and an ergonomic, coherent set of supporting features (message passing, supervisors). No function colours and all the baggage that comes with that. Less well discussed but no less important: it puts concurrency decisions in the hands of the function caller, not the implementer.
I understand Rust's focus on zero cost abstractions and, whilst I wouldn't pretend to understand the innards and consequences, get why green threads might not be compatible with that. OTOH that restriction doesn't hold for languages with a runtime like C# and Python. I'm increasingly convinced the compromises of async/await make it a poor language design for the concurrency problem when the language has a runtime.
Perhaps we'll see some comparitive studies now Java has green threads. Erlang is different from C#/Python in many ways so straight comparison is hard. Java is much closer to C# so should be a much better basis for comparison.
- neonsunset 3y agoThis post illustrates a common and unfortunate misconception about async/await. It's not "hurr durr don't block thread" which is where a lot of developers stop reading at, at their own loss. And then come asking about green threads in github issues in a classic X Y problem fashion. It is a paradigm where method calls represent an asynchronously produced result, a Task/Promise. Therefore, if all you do is always just await all the results right after calling async methods, you have not used the other 80% of the features. Task<T> is about composing, chaining and interleaving the tasks, sometimes hundreds or thousands at a time, to achieve (sometimes massively) parallel and concurrent execution of application logic. And we are blessed with C# making it as easy as it gets.
- anacrolix 3y agoYou don't need the syntax tho. You can do green threading without function colouring. Rust might be the only language with an excuse to do it without green threading but only insofar as async doesn't presuppose native threading. But then why not just have a trait when you need to ensure you're the only thing executing on a single thread.
- neonsunset 3y agoPlease re-read the comment, thank you. In addition, there are single-threaded and thread-per-core executors with different future bounds. It is that Tokio puts more requirements on Send and Sync because it is a proper implementation with worker-per-core (configurable to be otherwise) + work stealing.
- spinningslate 3y agoasync/await is a language design feature to enable fine-grained concurrency. Where "fine grained" means "more fine" than OS processes or threads allow. > Task<T> is about composing, chaining and interleaving the tasks, sometimes hundreds or thousands at a time, to achieve (sometimes massively) parallel and concurrent execution of application logic. Replace Task<T> with Erlang processes and the statement holds. Except without coloured functions; without the async decision being in the wrong place; without codebases where dual versions of functions proliferate (DoSomething() / DoSomethingAsync()). At its heart, concurrency is about being able to express multiple sequences of actions such that there's no undesired interaction between them when running. Thread blocking is one form of undesired interaction. So "hurr durr don't block thread" does matter even if it's not the only thing.
- neonsunset 3y agoIn C#, interleaving various tasks is as easy as var data1 = service1.GetData(); var data2 = service2.GetAnotherData(); var aggregate1 = Aggregate(await data1); var result = Handle(await aggregate1, await data2); No need to deal with writing three lines per each operation to just schedule it in a "fork" way like in Java. In "colorless" (which is always a lie) async runtimes you have to go out of your way to make it concurrent. Perhaps Erlang process isn't coarse grained abstraction as you say, but there are multiple aspects that make Erlang problematic. And again, I will not tire of repeating it - the article about function coloring is actively harmful to the industry and is leading hundreds of developers with concurrency knowledge gaps assume that they need to avoid Task/Future-based code like plague when it is actually the best abstraction we have today for massively concurrent processes (if it was badly designed in whatever language of your choice - sorry). In addition, because Task<T> is a thread-safe object in C#, you can apply all kinds of transformations and data chaining with LINQ on collections/sequences of those, or even together with parallel LINQ and tasks at the same time. Your simple average code will easily scale to all CPU cores if it does not have interdependencies/contention (a lot of LOB codebases don't, it's all straight line up to a DB or a third-party call(s)). And last but not least, all BEAM-based languages are comparatively slow (hard performance ceiling is always imposed if you don't pay with static typing and full JIT/AOT) and unfortunately suffer from high heap footprint, even compared to the more throughput-focused GC modes in .NET and GC implementations in JVM. But no, developers are insistent on parroting quotes said 10 to 15 years ago instead of at least attempting to assess technologies on their merits of today.