Live data from Hacker News

Why asynchronous Rust doesn't work

theta.eu.org

81–90 of 499 posts

Re: Why asynchronous Rust doesn't work

#81
post #15

Earlier quoted context omitted.

C# and C++ adopted basically the same model.

Note that C++ offers async as a library and not as a programming language feature which Bjarne Stroustrup is strongly against. He talk more about why in "The Design and Evolution of C++" but i don't have the material at hand. As far as i remember, his main argument was that there is no concurrency model to fit them all and thus it doesn't worth to add new syntax and semantics for a specific model except to make the P…

No without compiler support you can't do async in a library. Rust also does async in library so to speak.

Re: Why asynchronous Rust doesn't work

#82
post #49
post #6

As I read through the database example, I saw that the compiler just caught a multi-threading bug for the author, and instead of being thankful, he’s complaining that Rust is bad. I think he should use a higher level framework, or wait a few years for them to mature, and use a garbage collected language until then.

There wasn't any multi-threading in that example I think.

You created a DB on one thread and accessed / modified it on another.

Re: Why asynchronous Rust doesn't work

#83
post #76
post #26

I don't think any of this is actually a reason why async rust doesn't work. The function color problem is a bit overblown, it hasn't broken nodejs yet either. Most code is sync, sync can call async and vice versa, and the ecosystem hasn't come tumbling down yet (since most Rust isn't whichever async application runtime for web apps is currently in vogue - its a systems language after all). Either way there are bigger…

I really don't see a problem with function color in a typed language. Every function has color and compiler enforces you pass right color. Async is just another type that may have some convenient syntax. It might be inconvenient in untyped languages like js since you couldn't compose them.

It’s not a problem of being error-prone, the problem is that the ecosystem is split. As a crate author, do I implement my functions for color A or color B? Every crate author will eventually encounter this question and the inevitable fall out from making the wrong decision. Presently, the only way to deal with this is implement your functionality in both colors.

Re: Why asynchronous Rust doesn't work

#84
post #18

For a few months while I was between jobs, I decided to learn Rust. Because async code is supposed to be better than threaded code, I spent all my time trying to write async Rust. Big mistake! I never accomplished what I set out to accomplish. Most of my experience is in C#, where the difference between async and threaded code is mostly syntax sugar. (Until you get into the details.) (And async code makes writing UI…

The problem you were trying to solve (safe system level multi-threaded programming) is really really hard, and actually Rust makes it easier.

If you enjoy it, learn it and have fun doing high performance work at your new job.

If you’re not passionate about it, it’s OK, there are lots of work in other domains.

Re: Why asynchronous Rust doesn't work

#85
post #76
post #26

I don't think any of this is actually a reason why async rust doesn't work. The function color problem is a bit overblown, it hasn't broken nodejs yet either. Most code is sync, sync can call async and vice versa, and the ecosystem hasn't come tumbling down yet (since most Rust isn't whichever async application runtime for web apps is currently in vogue - its a systems language after all). Either way there are bigger…

I really don't see a problem with function color in a typed language. Every function has color and compiler enforces you pass right color. Async is just another type that may have some convenient syntax. It might be inconvenient in untyped languages like js since you couldn't compose them.

It's a problem in that you can't arbitrarily compose synchronous and asynchronous functions.

Many languages have a distinction between statements and expressions, and some language designers thought that was ugly and designed languages where everything is an expression.

But because of how people think, an application typically has a rough hierarchy to it by the designer's intent. So the fact that this becomes a bit more explicit because a language marks statements or async functions as having a specific place in that hierarchy isn't generally a bad thing.

Re: Why asynchronous Rust doesn't work

#86
The big issue is that non-GC concurrency is still effectively a CS research topic.

In a GC language, you can "just" let the GC system clean up after you're done--who owns allocation and cleanup isn't an issue.

In a non-GC language, who allocates and cleans up what and who pays for that suddenly becomes a fundamental part of the domain.

For example, I have seen a zillion "lock-free" data structure libraries in Rust, and I don't think I've seen even one that actually holds to even the basic amortization guarantees like java.util.concurrent.

Re: Why asynchronous Rust doesn't work

#87

A bigger problem in my opinion is that Rust has chosen to follow the poll-based model (you can say that it was effectively designed around epoll), while the completion-based one (e.g. io-uring and IOCP) with high probability will be the way of doing async in future (especially in the light of Spectre and Meltdown). Instead of carefully weighing advantages and disadvantages of both models, the decision was effectively…

Since you clearly have expertise, I'm curious if you might provide some insight into what would roughly be different in an async completion-based model & why that might be at a fundamental odds with the event-based one? Like is it an incompatibility with the runtime or does it change the actual semantics of async/await in a fundamental way to the point where you can't just swap out the runtime & reuse existing async…

It's certainly possible to pave over the difference between models to a certain extent, but the resulting solution will not be zero-cost.

Yes, there is a fundamental difference between those models (otherwise we would not have two separate models).

In a poll-based model interactions between task and runtime look roughly like this:

- task to runtime: I want to read data on this file descriptor.

- runtime: FD is ready, I'll wake-up the task.

- task: great, FD is ready! I will read data from FD and then will process it.

While in a completion based model it looks roughly like this:

- task to runtime: I want data to be read into this buffer which is part of my state.

- runtime: the requested buffer is filled, I'll wake-up the task.

- task: great requested data is in the buffer! I can process it.

As you can see the primary difference is that in the latter model the buffer becomes "owned" by runtime/OS while task is suspended. It means that you can not simply drop a task if you no longer need its results, like Rust currently assumes. You have either wait for the data read request to complete or to (possibly asynchronously) request cancellation of this request. With the current Rust async if you want to integrate with io-uring you would have to use awkward buffers managed by runtime, instead of simple buffers which are part of the task state.

Even outside of integration with io-uring/IOCP we have use-cases which require async Drop and we currently don't have a good solution for it. So I don't think that the decision to allow dropping tasks without an explicit cancellation was a good one, even despite the convenience which it brings.

Re: Why asynchronous Rust doesn't work

#88
post #23

Earlier quoted context omitted.

> So... don’t use first-class functions so much? It’s a systems language, not a functional language for describing algorithms in CS whitepapers. Then maybe it was a mistake to adopt an async paradigm from functional languages that relies heavily on the idea that first-class functions are cheap and easy? (FWIW I think Rust was right to pick Scala-style async; it's really the only nice way of working with async that I'…

> maybe it was a mistake to adopt an async paradigm from functional languages > I think Rust was right to pick Scala-style async I'm confused by this assertion. I'm more aware of procedural language origins of syntactic async/await than functional? The scala proposal in 2016 for async/await even cites C#'s design (which came in C# 5.0 in 2012) as an inspiration[1]. From there, it appears python and typescript added t…

> I'm more aware of procedural language origins of syntactic async/await than functional? The scala proposal in 2016 for async/await even cites C#'s design (which came in C# 5.0 in 2012) as an inspiration[1].

The C# version comes from F# (2007) which was in turn inspired by the "Poor Man's Concurrency Monad" implementation for Haskell (1999) (in turn inspired by Concurrent Haskell and, ultimately, Concurrent ML). It's very much a functional lineage.

Re: Why asynchronous Rust doesn't work

#89
post #57

I like to joke that the best way to encounter the ugliest parts of Rust is to implement an HTTP router. Hours and days of boxing and pinning, Futures transformations, no async fn in traits, closures not being real first class citizens, T: Send + Sync + 'static, etc. I call this The Dispatch Tax. Because any time you want more flexibility than the preferred static dispatch via generics can give you - oh, so you just w…

In a systems context, where performance and memory ostensibly matter, why wouldn’t you want to be made aware of those inefficiencies?

Sure, Go hides all that, but as a result it’s also possible to have memory leaks and spend extra time/memory on dynamic dispatch without being (fully) aware of it.

Re: Why asynchronous Rust doesn't work

#90

Earlier quoted context omitted.

> maybe it was a mistake to adopt an async paradigm from functional languages > I think Rust was right to pick Scala-style async I'm confused by this assertion. I'm more aware of procedural language origins of syntactic async/await than functional? The scala proposal in 2016 for async/await even cites C#'s design (which came in C# 5.0 in 2012) as an inspiration[1]. From there, it appears python and typescript added t…

> If anything, async-await feels like an extremely non-functional thing to begin with Futures/promises (they mean different things in different languages), like many other things, form monads. In fact async-await is a specialization of various monad syntactic sugars that try to eliminate long callback chains that commonly affect many different sorts of monads. Hence things like Haskell's do-notation are direct precur…

I'm not clear on if this is supposed to be disagreement or elaboration or education.

The fact that in a language like Haskell, you can perform something like async-await with futures (which are absolutely a kind of monad) in a natural way is precisely what I had in mind with what you quoted.

Regardless, the specific heritage of async-await syntax seems rooted in procedural languages (that do borrow much else as well from functional languages, yet are still not functional in any meaningful sense) like C# and python. They are absolutely an attempt to bring some of the power of something like monadic application (including do notation) into a procedural environment as an alternative to threads (green or otherwise), which hide the execution state machine completely.

Post reply on HN