Live data from Hacker News

Why asynchronous Rust doesn't work

eta.st

131–140 of 305 posts

Re: Why asynchronous Rust doesn't work

#131

Can someone explain to me the attraction of async programming? I don't really do JS, where a lot of this seems to be happening, but the code I have seen with the huge ladders of callbacks doesn't seem so great to work with to me. Also, although using promises seems better, it seems like it could quickly become spaghetti.

If you mean non-blocking in general, the benefit is that your system can do something else useful while it's waiting for some operation to complete (usually things accessing files or a database or a network service)

If you specifically mean async/await syntax, let me illustrate with a contrived example. It can let you express a sequence of asynchronous operations in a more natural way:

  function promised(cache, db, metrics) {
    return cache.query(...).then(cachedResult => {
      if (cachedResult) {
        return cachedResult;
      } else {
        return db.query(...).then(dbResult => {
           return cache.store(dbResult).then(_ => dbResult);
        });
      }
    }).then(finalResult => {
      metrics.log(...);
      return finalResult;
    });
  }
  
  async function awaited(cache, db, metrics) {
    let result = await cache.query(...);
    if (!result) {
      result = await db.query(...);
      await cache.store(result);
    }
    metrics.log(...);
    return result;
  }

Re: Why asynchronous Rust doesn't work

#132

Can someone explain to me the attraction of async programming? I don't really do JS, where a lot of this seems to be happening, but the code I have seen with the huge ladders of callbacks doesn't seem so great to work with to me. Also, although using promises seems better, it seems like it could quickly become spaghetti.

Essentially, the attraction is being able to wait for multiple things at the same time within a single thread. It's useful for things like webservers that want to handle thousands of connections simultaneously, but most of these connections aren't actually doing anything useful, they are waiting on the filesystem or the database connection or some other network service. And you can't really spawn thousands of OS threads because those have non-trivial overhead.

Now, you may think this can be done in C with the `select()` API and many switch statements. And you would be correct. All these "async" languages and framework are wrappers around this that let you write your code in a procedural manner, and take care of the select and switch for you.

Re: Why asynchronous Rust doesn't work

#133
post #124
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 see this article as not understanding the goals and tradeoffs of Rust. The author would be happier writing in a higher-level language than Rust. That's a pointless conclusion. The author's criticisms of Rust's tradeoffs are invalid because those are the tradeoffs Rust made. A perfect circle!

That would be circular, but that's not what the parent is saying. Rather, eta's post has one central point - she even bolds it for us:

> Rust is not a language where first-class functions are ergonomic.

And this... I mean, I don't agree with her, but that might be because I've been immersed in Rust for half a decade. But Rust's tradeoffs are based around four things. It is a:

- performant - reliable (incl. memory safe) - productive - systems programming language

"Systems programming language" means no garbage collector. "Reliable" means you can't just pass around references to memory willy-nilly. I'm sure closures and their associated traits (Fn(), "call it as many times as you want", FnMut(), "call it only when certain safety conditions are satisfied", and FnOnce(), "call it once") could have been fine-tuned more, but they _do_ achieve the goal of general, usable (imo) first class functions.

I don't see another design that would have done this.

Re: Why asynchronous Rust doesn't work

#134
post #73
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…

The article is also conflating synchronous single-threaded, synchronous multi-threaded and asynchronous programming. Each have their own usage, and no, a multi-threaded program is not the same as an asynchronous one. For example, using threads and channels instead of async/await is not a design flaw if your workload is mostly about large, blocking computations on a read-only shared state with no I/O. In that situatio…

its really strange that there are two languages running around together. one which is very opinionated in how to manage memory in a stack discipline and another which just uses reference counts.

they don't quite mix. so you need to be aware of which one you're (implicitly using), and you may need library functions for both colors.

you have to admit this adds some additional mental overhead. but what got me when trying to understand the language was just that there _was_ such a division. I actually tried to apply the lifetime model to asynch objects.

Re: Why asynchronous Rust doesn't work

#135
post #77

Earlier quoted context omitted.

I think it's not entirely fair to paint problems with rust's async features as an aversion to low-level-ness. If anything, I think the issue with Rust's async is that it tries to be too high level . In my experience with async rust, most of the difficulty comes from "spooky errors at a distance". I.e, you're writing some code which feels completely normal, and then suddenly you are hit with a large, obtuse error mess…

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)

>designed specifically around async like Go is, which some profound tradeoffs to make it happen.

Go was not designed around the idea of "async". Its goroutine approach was inspired by https://en.wikipedia.org/wiki/Communicating_sequential_proce..., a nice theoretical model for concurrency.

Re: Why asynchronous Rust doesn't work

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

> But such a type doesn't really mention the lifetimes of whatever it captures, so in practice it doesn't work well in Rust.

It can: Box R + 'a>

This is just the general syntax for any trait object with a lifetime.

Re: Why asynchronous Rust doesn't work

#138

There are constant efforts to make async easier in all languages. It'll never be as easy as writing synchronous code. I really don't like futures/promises, I don't know where this abstraction came from. Callbacks are where it's at. Someone, somewhere has to write callback code; they cannot be got rid of. What works for me is keeping the callback handler as short as possible, this usually means just pushing 'work' ont…

Callbacks are insufficient. They do not handle pythons with or javas try-with-resources, making a lot of code break completely. E.g. metrics.

Re: Why asynchronous Rust doesn't work

#139

I don't have any experience with async Rust (but I stuggled a lot with Rust's closures when I dabbled with Rust a while back so I can at least feel the pain the article tries to convey), but one important reason to not build async-await on top of fibers or threads but instead on code transformation (aka 'compiler magic') is 'weird architectures' like WASM, which doesn't have easy access to threading (locked behind CO…

I think the article is just... wrong about async and closures. You're right that async Rust simply doesn't deal with them, because (contrary to the article) they're not used in the async compiler transformation.

Re: Why asynchronous Rust doesn't work

#140
post #98

Earlier quoted context omitted.

I don't disagree. After working with Rust's model, which forces you to confront a lot of the tradeoffs and complexity, I'm more inclined to think async is a feature which should really be considered from the ground up when a language is being designed, to avoid painting oneself into a corner in the design space.

Rust could never have had easy async like Go, though, and maintain the control of performance that is the whole point of Rust.

Rust had GC in earlier versions, see eg http://web.archive.org/web/20130607161259/http://pcwalton.gi...
Post reply on HN