Live data from Hacker News

Why asynchronous Rust doesn't work

theta.eu.org

191–200 of 499 posts

Re: Why asynchronous Rust doesn't work

#191
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…

> Note that C++ offers async as a library and not as a programming language feature which Bjarne Stroustrup is strongly against.

https://www.modernescpp.com/index.php/c-20-coroutines-the-fi...

Re: Why asynchronous Rust doesn't work

#192
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.

I think Rust is also able to hide certain things. Without async things are fine:

    type Handler = fn(Request) -> Result, Error>; 
    let mut map: HashMap = HashMap::new(); 
    map.insert("/", |req| { Ok(Response::new("hello".into())) }); 
    map.insert("/about", |req| { Ok(Response::new("about".into())) });
Sure, using function pointer `fn` instead of one of the Fn traits is a bit of a cheating, but realistically you wouldn't want a handler to be a capturing closure anyway.

But of course you want to use async and hyper and tokio and your favorite async db connection pool. And the moment you add `async` to the Handler type definition - well, welcome to what author was describing in the original blog post. You'll end up with something like this

    type Handler = Box BoxFuture + Send + Sync>; 
    type BoxFuture = Pin + Send>>;
plus type params with trait bounds infecting every method you want pass your handler to, think get, post, put, patch, etc.

    pub fn add(&mut self, path: &str, handler: H)
    where
        H: Fn(Request) -> F + Send + Sync + 'static,
        F: Future + Send + 'static,
And for what reason? I mean, look at the definitions

    fn(Request) -> Result, Error>;
    async fn(Request) -> Result, Error>;
It would be reasonable to suggest that if the first one is flexible enough to be stored in a container without any fuss, then the second one should as well. As a user of the language, especially in the beginning, I do not want to know of and be penalized by all the crazy transformations that the compiler is doing behind the scene.

And for the record, you can have memory leaks in Rust too. But that's besides the point.

Re: Why asynchronous Rust doesn't work

#193

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…

> A bigger problem in my opinion is that Rust has chosen to follow the poll-based model

This is an inaccurate simplification that, admittedly, their own literature has perpetuated. Rust uses informed polling: the resource can wake the scheduler at any time and tell it to poll. When this occurs it is virtually identical to completion-based async (sans some small implementation details).

What informed polling brings to the picture is opportunistic sync: a scheduler may choose to poll before suspending a task. This helps when e.g. there is data already in IO buffers (there often is).

There's also some fancy stuff you can do with informed polling, that you can't with completion (such as stateless informed polling).

Everything else I agree with, especially Pin, but informed polling is really elegant.

Re: Why asynchronous Rust doesn't work

#194
post #39

> And, as I said at the start, that makes me kinda sad, because I do actually like Rust. I think that’s the most important part of the article. People like Rust but it’s becoming more complex than C++. But unlike C++ it’s more difficult to pick and choose what you use. Rust’s death will be one by thousand cuts. “I really like the language but can’t justify all that complexity in my new small and simpke project” is wh…

> But unlike C++ it’s more difficult to pick and choose what you use.

Can you expand on this point?

Re: Why asynchronous Rust doesn't work

#195
post #185

I'll repeat this until my karma is zero: Erlang, Rust and Go have simple memory models and cannot do Joint (on the same memory) Parallelism efficiently. They are only fragmenting development. In my opinion there are only two programming languages worth mastering: C+ (C syntax compiled with cl/g++) on client and Java SE (8u181) on server. That said C++ (namespaces/string/stream) and JavaScript (HTML5) can be useful fo…

Why Java 8 as opposed to the latest JDK? And what about C#? It's in a similar boat as Java. Also, how is the Java memory model different from Go for this use case? They both allow mutation by sharing.

Java 8 is the last free Oracle JDK, nothing added after 8 is really interesting enough to take the complexity hit that Java 9/10/11 etc. mean.

I'm waiting for user space network, that is the last feature that will make the switch worth: my system uses almost as much kernel copy CPU as my user space process!!!

C# is an ok alternative but they went for value types instead of sticking to the VM. Java has atleast 10 years head start on C#, also Microsoft.

Go has no VM but uses GC, thay miss half of the requirements to make Joint Parallelism!

WebAssembly has a VM but no GC, that is more interesting, unfortunately there is no glue code in the reference implementations!

Re: Why asynchronous Rust doesn't work

#196
post #189

Earlier quoted context omitted.

I agree that Rust async is currently in a somewhat awkward state. Don't get me wrong, it's usable and many projects use it to great effect. But there are a few important features like async trait methods (blocked by HKT), async closures, async drop, and (potentially) existential types, that seem to linger. The unresolved problems around Pin are the most worrying aspect. The ecosystem is somewhat fractured, partially…

Is there a good explanation on the difference between polling model and completion model? (not Rust-specific)

Further down the thread: https://news.ycombinator.com/item?id=26407770

Re: Why asynchronous Rust doesn't work

#197
post #129
post #30

I've been primarily coding in rust since 2018. I never cared for async/await, and I've never used it. (at some point, coding event loops became very natural/comfortable for me, and I have no trouble writing "manual" epoll code with mio/mio_httpc). one nice thing about rust's async/await is, you don't have to use it, and if you don't, you don't pay for it in any way. sure, I run into crates that expect me to bring in…

I don't know how anybody can say this with a straight face. Even in a systems context I think it's pretty reasonable to want to either perform or receive a HTTP request, as soon as you do that in Rust you are funneled into Hyper or something built on top of it (like reqwest) and instantly are dependent on tokio/mio. The very first example in the reqwest readme^1 has tokio attributes, async functions AND trait objects…

Reqwest lets you choose between async or not. It has a "blocking" module with a similar API, but no async functions.

https://docs.rs/reqwest/0.11.2/reqwest/blocking/index.html

(Maybe this uses async rust under the hood, but you don't have to care about it)

Re: Why asynchronous Rust doesn't work

#198
post #185

I'll repeat this until my karma is zero: Erlang, Rust and Go have simple memory models and cannot do Joint (on the same memory) Parallelism efficiently. They are only fragmenting development. In my opinion there are only two programming languages worth mastering: C+ (C syntax compiled with cl/g++) on client and Java SE (8u181) on server. That said C++ (namespaces/string/stream) and JavaScript (HTML5) can be useful fo…

Humans waste billions of hours and dollars in casinos - apply your efforts here and you’ll help the human race much more.

Re: Why asynchronous Rust doesn't work

#199
post #185

I'll repeat this until my karma is zero: Erlang, Rust and Go have simple memory models and cannot do Joint (on the same memory) Parallelism efficiently. They are only fragmenting development. In my opinion there are only two programming languages worth mastering: C+ (C syntax compiled with cl/g++) on client and Java SE (8u181) on server. That said C++ (namespaces/string/stream) and JavaScript (HTML5) can be useful fo…

Can you give an example that C+ can do efficiently that Rust cannot do efficiently even with ‘unsafe’?

Re: Why asynchronous Rust doesn't work

#200
post #53

Earlier quoted context omitted.

Could Rust switch? More importantly, would a completion based model alleviate the problems mentioned?

Without introducing Rust 2? Highly unlikely. I should have worded my message more carefully. Completion-based model is not a silver bullet which would magically solve all problems (though I think it would help a bit with the async Drop problem). The problem is that Rust async was rushed without careful deliberation, which causes a number of problems without a clear solution in sight.

> The problem is that Rust async was rushed without careful deliberation, which causes a number of problems without a clear solution in sight.

Are we talking about the same Rust? I remember the debate and consideration over async was enormous and involved. It was practically the polar opposite of “without careful deliberation”.

Post reply on HN