Live data from Hacker News

Why asynchronous Rust doesn't work

eta.st

221–230 of 305 posts

Re: Why asynchronous Rust doesn't work

#221
post #199

"Maybe we could just have kept Rust as it was circa 2016, and let the crazy non-blocking folks write hand-crafted epoll() loops like they do in C++. I honestly don’t know, and think it’s a difficult problem to solve." I think this is the most underappreciated part of this article. Since when did everything have to be async? There are other ways to represent concurrency that more accurately reflect what the computer i…

> let the crazy non-blocking folks write hand-crafted epoll() loops like they do in C++.

> I think this is the most underappreciated part of this article.

I think it's incredibly silly actually. Abandon all async for a difficult and error prone epoll model?

> Since when did everything have to be async?

It doesn't! No one is forcing anyone to use async. I'm not sure why the author implies that.

But if you do want to use async, Rust is attempting to solve the async problem with the same guarantees it has for blocking code. Turns out that is hard.

Re: Why asynchronous Rust doesn't work

#222
post #122

Earlier quoted context omitted.

Rust has stopped depending on closures for async when it moved from experimental futures library to built-in async/await. Rust now easily supports mutable and temporary references in async blocks and across await points. Rust still doesn't support use-after-free, so you can't reference a temporary object and use it in another thread that will outlive it :) In TFA the second do_work_and_then() example doesn't compile,…

You can't do that using anything here? https://doc.rust-lang.org/std/mem/index.html Genuine question, I don't mess around with memory typically.

forget takes owned values. So you wouldn't have a handle to them to use after.

Re: Why asynchronous Rust doesn't work

#223
post #106

Earlier quoted context omitted.

Naive synchronous reference counting can lead to large pauses as well. What happens when you drop the last reference to the root of a 10,000-node search tree? You do 10,000 reference deferments and free()s. Reference counting might feel more incremental than GC, but really is not. There are tricks you can use, but you're better off with a fast, modern, pauseless real GC that comes with tons of other benefits. Look: m…

> Naive synchronous reference counting can lead to large pauses as well. What happens when you drop the last reference to the root of a 10,000-node search tree? > You do 10,000 reference deferments and free()s. You do all that work at the precise point where the last reference was dropped . What people who complain about GC pauses dislike is the GC causing pauses in completely unrelated threads, including these threa…

Reference counting implies non deterministic frees. If you knew who the final owner of an object was, you wouldn't need reference counting.

While it is true that many (most?) GCs have STW sections, it's not at all clear that it is a bad tradeoff.

Re: Why asynchronous Rust doesn't work

#224

Earlier quoted context omitted.

`Rc` freezes the value as long as it's shared unless you use interior mutability. It's fine when you want to share immutable data, but if you ever need to mutate its contents you will have to deal with awkward cases and situations, and at runtime! Wrapping everything in `Rc` is not a good default strategy. Instead figure out an architecture that works well with the borrow checker! This normally means thinking hard ab…

> If it's hard, then it's probably wrong! Trees and graphs?

What the problem with trees? They are trees, not cyclic graphs.

Re: Why asynchronous Rust doesn't work

#225
post #7

The article glosses over async Rust and is mostly a rant about how closures are difficult in Rust. Most of the difficulty comes from Rust not having a GC yet wishing to keep track of object lifetimes precisely: a GC'ed language needs no distinction between an ordinary function pointer and a closure that captures the environment. But Rust being a low-level systems language chose not to have a GC. Another popular langu…

Some of the pain inflicted by async Rust is incidental, not due to this GC choice. Pin is the biggest culprit.

Pin exists so that references captured in Futures may be implemented via raw pointers. This implies that a Future contains pointers to itself, hence Pin.

The cost of Pin is that it forces you to write unsafe code as a matter of course, the so-called pin-projections. [1] Look at the requirements for structural pinning: they are quite complicated.

References captured in Futures probably could have been implemented differently: base + offset, or relocations, or limit what can be captured, or always Box the state for a Future that captures a reference. Those would have avoided a GC and been even safer, since it wouldn't require unsafe code on the part of struct implementors.

1: https://doc.rust-lang.org/std/pin/#projections-and-structura...

Re: Why asynchronous Rust doesn't work

#226

Earlier quoted context omitted.

Honestly, as a consumer of libraries, I much prefer when they're written in Rust (without gratuitous use of `unsafe`) compared to a language which doesn't make you think about these sorts of things as hard.

For me, writing a program is mostly writing a bunch of libraries that I then put together. So I am consuming my libraries mostly myself. Therefore, for me it is important that both the library writing and the library using can be done efficiently. I assume that having a Rust library of something is a good thing. The question for me is: How easy and natural and quick is it to express a concept as a library in Rust?

Nobody can answer this question unless you tell us what kind of concepts and libraries you are writing.

Sometimes Rust is handcuffs, sometimes it is guardrails, sometimes it is a rollercoaster track.

It is impossible to tell without more information. You and the other guys are asserting things with basically no knowledge of the other's context.

Re: Why asynchronous Rust doesn't work

#227
post #7

The article glosses over async Rust and is mostly a rant about how closures are difficult in Rust. Most of the difficulty comes from Rust not having a GC yet wishing to keep track of object lifetimes precisely: a GC'ed language needs no distinction between an ordinary function pointer and a closure that captures the environment. But Rust being a low-level systems language chose not to have a GC. Another popular langu…

Some of the pain inflicted by async Rust is incidental, not due to this GC choice. Pin is the biggest culprit. Pin exists so that references captured in Futures may be implemented via raw pointers. This implies that a Future contains pointers to itself, hence Pin. The cost of Pin is that it forces you to write unsafe code as a matter of course , the so-called pin-projections. [1] Look at the requirements for structur…

I don't think base + offset would have worked because then references would have to be codegen'd differently depending on whether they're in a future or not; this would have impacted separate compilation as you can pass references to other functions (including across FFI). Relocations only work at load time (either dynamic linking or link time), so they wouldn't work. Limiting what can be captured was tried with the old futures crate and it was a real nuisance. Boxed futures violate the zero-cost abstractions principle, which is the reason why many Rust users are using the language in the first place.

Pin is an evil, but it's the least evil of the possible options.

Re: Why asynchronous Rust doesn't work

#228

Earlier quoted context omitted.

This may be a problem with async generally unless the language is designed specifically around async like Go is, which some profound tradeoffs to make it happen. (not criticizing that I think Go did a great job)

Zig managed to get async correct, if you ask me, but it's because I would call it "the lowest-level primitive to do what you need it to do" (shift the function frame over to a place that "might not be the stack"). If you think of it as a sugared "async" you will probably do it wrong. After a lot of wrassling with it, once I realized that it was a very shallow abstraction over what the hardware is actually doing, ever…

Having a global switch to switch the program over to async only works if all your concurrency primitives are aware of it: e.g. mutexes. Otherwise you get deadlocks. But Rust is designed to work with raw OS concurrency primitives. So that solution isn't available.

Re: Why asynchronous Rust doesn't work

#229
post #192

Earlier quoted context omitted.

Zig's approach is really nice here, but it's also a notably easier problem to solve than rust has, since it's not trying to solve for parallel/concurrent safety. Do you think Zig's approach would be feasible in Rust? I guess maybe you could do it, but the sync version would have to have the stricter constraints of the async version.

I'm holding out for formal-methods based static analysis on lifetimes in zig.

Not possible for the same reasons why just adding a borrow checker to C++ isn't possible. Mostly this comes down to incompatibility with existing code. Zig is just not memory safe, and the only solution would be to add a GC.

Re: Why asynchronous Rust doesn't work

#230
post #7

The article glosses over async Rust and is mostly a rant about how closures are difficult in Rust. Most of the difficulty comes from Rust not having a GC yet wishing to keep track of object lifetimes precisely: a GC'ed language needs no distinction between an ordinary function pointer and a closure that captures the environment. But Rust being a low-level systems language chose not to have a GC. Another popular langu…

I agree that this one isn't about async Rust at all. The main comparison is drawn in

> And then fast forward a few years and you have an entire language ecosystem built on top of the idea of making these Future objects that actually have a load of closures inside

And this sentence is wrong. There's next to no `Future` implementations which are built on top of callbacks. And the reason why that's the way it is is exactly the one the author mentions: Callbacks don't work very well with Rusts ownership model.

Post reply on HN