Live data from Hacker News

Why asynchronous Rust doesn't work

eta.st

151–160 of 305 posts

Re: Why asynchronous Rust doesn't work

#151
post #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, me…

In your async example, each await could just be a blocking operation - it’s all serialized. The blocking sleeps, yielding the processor for other work. Like, maybe context switching is a little more expensive, maybe a normal thread’s stack consumes more memory than an async context.

The utility of native async is when you spawn multiple async tasks before awaiting. This is cheaper than spinning up some threads or handing off to a threadpool.

Re: Why asynchronous Rust doesn't work

#152
I run a team at work building a desktop application in Rust which handles live streaming market data and displays it in an arbitrary layout defined by the user. From our experience (and we have a very good Rust team), async Rust works fantastically well.

https://cryptowat.ch/desktop

Re: Why asynchronous Rust doesn't work

#153

Earlier quoted context omitted.

Correct me if I'm wrong, but: - GC pauses, Rc does not, it's simply a deallocation by the last reference holder - Rc still has predictable memory allocation/deallocation, GC is not guaranteed to run until needed - More efficient memory use, no need to keep track of allocated objects - The rest of the Rust language is a pleasure to use (imo) - Python is slow for certain applications, and not concurrent - Kotlin is kin…

> GC pauses, Rc does not, it's simply a deallocation by the last reference holder There are pauseless GCs (e.g., Azul for JVM), and Go kicked off a trend of super-low-latency GC. Also, RC deallocation is O(N) while GC is usually O(1) (ignoring pedantry about how RC is a type of GC). Further, RC can't handle cycles automatically. > Rc still has predictable memory allocation/deallocation, GC is not guaranteed to run un…

> I'm not sure what the bookkeeping overhead is for tracing GCs, but I'm guessing it's not O(N)?

I don't know about these days but, historically, the received wisdom was "Take the memory your algorithm should need and double it, to leave room for floating garbage and bookkeeping overhead. Otherwise, your performance will suffer as the GC is forced to run more frequently than is ideal."

("Floating garbage" being the jargon for stuff that's inaccessible but not yet collected.)

Re: Why asynchronous Rust doesn't work

#154

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…

I wonder if you could just pass this 10000 tree node root to another thread that will just drop it. This should result in no pause for main thread. Apparently you need Arc for that not Rc which shouldn't have much overhead over Rc in reasonable scenarios.

Yes, doing big drops in a subthread is a good way of avoiding pauses when dropping large objects of any kind.

Re: Why asynchronous Rust doesn't work

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

C++ lambdas are much better than Rust ones, because you can explicitly decide what to copy inside of the closure.

As for the author being happier writing in a higher level language, it kind of proves the point that Rust's main target is the domain where any sort of automatic memory management aren't a viable option.

Pushing Rust outside of this domain is only trying to fit a square peg into a round hole.

Re: Why asynchronous Rust doesn't work

#156
The author ends this with a now apparently trendy Common Lisp yearning, but ironically, Common Lisp's async story is pretty weak, too. On the other hand, at least it didn't infect the whole ecosystem, just the projects that use certain libraries.

Re: Why asynchronous Rust doesn't work

#157

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…

I wonder if you could just pass this 10000 tree node root to another thread that will just drop it. This should result in no pause for main thread. Apparently you need Arc for that not Rc which shouldn't have much overhead over Rc in reasonable scenarios.

Yes, that is how C++/WinRT handles cascading deletion of COM instances, however when you are going down that route, it is basically a poor man's tracing GC.

Re: Why asynchronous Rust doesn't work

#158

Earlier quoted context omitted.

And suffer a 100 MB runtime? If anything, Rust with refcounts for everything is much closer to Swift.

Ah didnt realize swift has no runtime. Thanks!

Every language has a runtime, it is what supports the basic language infrastructure, including Swift.

https://github.com/apple/swift/blob/main/docs/Runtime.md

Re: Why asynchronous Rust doesn't work

#159

Earlier quoted context omitted.

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

Yes, and (to be clear to people who don't click your link) it was removed for exactly the reason that the parent commenter mentioned. Rust's lack of a pervasive GC is not intended to suggest that GC is not generally useful (even in a systems context), only that it's too difficult to satisfy the sort of extreme control that people demand of a low-level language if they are forced to find ways to work around the pervasive GC. Which is to say, you need a way to turn off the GC, and if you can function with the GC off, then maybe you should push that as far as you can get away with, which is what Rust did.

Re: Why asynchronous Rust doesn't work

#160
post #155
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…

C++ lambdas are much better than Rust ones, because you can explicitly decide what to copy inside of the closure. As for the author being happier writing in a higher level language, it kind of proves the point that Rust's main target is the domain where any sort of automatic memory management aren't a viable option. Pushing Rust outside of this domain is only trying to fit a square peg into a round hole.

C++ lambdas need that feature because they don't have lifetimes or a borrow checker. Rust closures don't need that feature because rust has a borrow checker that ensures you aren't referencing something you shouldn't be.

You can explicitly decide what to copy inside a Rust closure as well, you just use a `move` closure and create references for anything you need referenced outside the closure instead.

Post reply on HN