Live data from Hacker News

A four year plan for async Rust

without.boats

221–230 of 236 posts

Re: A four year plan for async Rust

#221

Adding Move and deprecating pin/unpin would be a huge ergonomic improvement I think. I also think the Rust project should consider “out-of-band” editions if they can deliver big features like that sooner rather than waiting until 2027.

Note that in general, the Rust project has chosen a time-based, not feature-based, release model. New Rust versions come out every 6 weeks, and new Rust editions have a consistent cadence of every 3 years. There are advantages and disadvantages to debate between time-based and feature-based release models, but Rust pretty clearly has chosen their preference.

The important aspect of the 6-week releases is that they’re frequent, so nobody feels a need to rush a feature to cram into the next big release.

Editions happening every 3 years unfortunately undo this, and there is a pressure to land changes before the upcoming edition.

Re: A four year plan for async Rust

#222

Earlier quoted context omitted.

I agree with most of this. > without needing to get into the weeds of threading A thread is the exact concept needed to describe that and preserve “if else then” sequential code. > 1000s of threads Linux handles thousands of threads just fine. If you’re using a scripting language like python, context switching is the least of your performance concerns.

> A thread is the exact concept needed to describe that and preserve “if else then” sequential code. I suggest looking at C# and Javascript that implement async very, very well. The difference is that with conventional threading semantics, when you join a thread, it doesn't return a result. You still need to write some kind of "thing" to get your result from the subthread to whatever's waiting on it. (C# also provide…

> C#/JavaScript

I am familiar with how these are implemented. My opinion is the same. Yes you can implement slightly lighter weight threads in a language itself.

> It doesn't matter what OS you're on, each thread needs its own allocated stack space and has the overhead of context switching

This is a quantitative question. I know what it does, the question is how much slower it is than whatever async construct you want to use.

Re: A four year plan for async Rust

#223
post #173

Earlier quoted context omitted.

Huh, thats rather odd argument. It is like saying no one is stopping anyone to write new low level, memory-safe programing language, that won't have Rust style async system. If there is real market demand it could fairly popular project. DB drivers, http servers, runtimes and so many other complex components are preferences of high skilled developers and not some objective market choices. Once its developed most appl…

One thing about Rust is that it's a fairly young language. We've had to implement a number of things ourselves that we wouldn't have had to implement in other languages. If there's not enough community interest for there to already exist a solution for your problem, you really only have three options: write it yourself (including opening a PR to add it to an existing implementation), pay someone to write it, or switc…

postgres is a wrapper around block-on(tokio-postgres).

Re: A four year plan for async Rust

#224

Earlier quoted context omitted.

> Probably worth revisiting those discussions to see where this has been thought through by the Rust team The issue generated a lot of hot air at the time, far more than I have time to read, but I think I have the gist of it. The performance issues were due to an implementation choice. All green thread implementations I'm aware of hide the code colouring event driven I/O introduces, and Rust did the same. The hiding…

That’s part of it, but it is also important that rust be an embeddable language. Ideally you should be able to replace a small component of a larger C or C++ program with Rust. Having a big fat runtime you’ve got to include before running any rust code makes that pretty much a non-starter.

> Having a big fat runtime you’ve got to include before running any rust code makes that pretty much a non-starter.

Just reasoning aloud here. That looks to be another similarity with green threads and async. Async also requires a big fat runtime that isn't part of the language. Instead you have to pick an async colour - such as tokio. That's pretty much what happens with green threads now. You have to pick a runtime such as the "may" crate, which forces the programmer to choose yet another colour.

So many colours, yet they are all just event loops underneath. Colours cause fragmentation, fragmentation is the mortal enemy of reuse.

It seems like the very least the language could do is provide a set of trait's for event driven I/O that mirror the existing I/O library in std. Then the library writers wouldn't have to colour their code by using a particular event loop implementation. I suspect it's easy enough for green threads or async, but accommodating both styles of event loop would be hard.

Re: A four year plan for async Rust

#225
post #56

I was a huge opponent of Rust, but finally decided to give it a try in anger once again. I began writing a large application, and noticed that many of my libraries only offered async versions, and the promise was quite appealing -- not having to worry about threads or concurrency as long as I followed certain rules. What I ended up with was an incredibly slow application because of the limitations of Rust async, and…

In the words of Steve Jobs, “you’re holding it wrong”. I’m guessing your code is blocking. You absolutely cannot do blocking code in async in any language, unless the blocking is super quick. No blocking io. async code should yield great performance if you are doing everything the right way. Yes it is single threaded but either run multiple threads in rust or run multiple instances of your program with systemd. That…

Right, I think async is bad. We have threads, and operating system level isolation with processes. For the most part, these primitives work fine.

My code wasn't blocking, but it did a very small amount of computation, locked on what was typically a highly contended (async) lock, and then dispatched a bunch of blocking I/O operations. Each of these turned into a context switch under the hood.

There were parts of my code that were computer intensive, but determining that without being able to use my normal tools was a pain, and I had to come up with heuristics of whether or not to dispatch with spawn_blocking, since the call had significant overhead.

An abstraction that was meant to simplify program resulted in me spending a lot more time staring at it.

I think one difference with Python is that the async implementation doesn't try to hide or abstract I/O away from you. If you're doing I/O, you know you're going to block, and thus you're forced to acknowledge it by spawning it on another thread.

Re: A four year plan for async Rust

#226
post #56

I was a huge opponent of Rust, but finally decided to give it a try in anger once again. I began writing a large application, and noticed that many of my libraries only offered async versions, and the promise was quite appealing -- not having to worry about threads or concurrency as long as I followed certain rules. What I ended up with was an incredibly slow application because of the limitations of Rust async, and…

> All of my I/O got pushed through one thread (with tokio) In all my use of Tokio in the last few years, I never heard of such a thing. In tokio::fs::File [1] it calls spawn_mandatory_blocking to do file writes, I assume this is similar to spawn_blocking [2] which sends a task to Tokio's blocking thread pool. That thread pool is supposed to max out at 512 blocking threads [3], unrelated to CPU core count. Tokio's Tcp…

So, it wasn't actually synchonrizing all of the I/Os onto one thread, but I wasn't getting any parallelism due to the amount of time required to dispatch I/Os. Essentially, my program was highly concurrent, but I wasn't able to get any I/O parallelism because each syscall was pretty cheap, and the cost of dispatching each I/O was too expensive.

Re: A four year plan for async Rust

#227

Earlier quoted context omitted.

At least on Windows I've reconfigured the stack space. (I had to run an experiment that required a lot of threads.) Is this something that's hard to do on Linux?

It's the same, but this issue gets to one of the hearts here: Both of these APIs are set by you, the user. You can choose how big to set your stack size, it's true. However, what value do you actually set? Too high, and you're still using too much memory, though admittedly less. Too low, and you either need to accept death by stack overflow, or runtime detect this case and fix things up. With async/await in Rust, the…

> Both of these APIs are set by you, the user. You can choose how big to set your stack size, it's true. However, what value do you actually set? Too high, and you're still using too much memory, though admittedly less. Too low, and you either need to accept death by stack overflow, or runtime detect this case and fix things up.

This is a solved problem - it's "just" the longest path in a call graph where each node is weighted by its function's stack frame size.

> With async/await in Rust, the compiler can statically see how large the stack size needs to be. Each "thread" will have a perfectly sized stack. No user intervention required, no fiddling with settings.

There is nothing stopping a compiler from doing the exact same analysis for a sync function at compile time (barring exceptions like varargs or deliberate recursion). They just... haven't, for some reason. It's a shame that it took until Zig for it to be addressed.

Re: A four year plan for async Rust

#228

Earlier quoted context omitted.

async took off when multicore processors came out and C had no first class way of running in parallel, so we bolted on threading libraries that are second class. Take a look at zig’s approach to concurrency, it’s so first class you can write your own event loop without an OS, i.e you could use the language’s async to write an OS.

Async doesn’t really have much to do with multicore. Indeed the most used async environment on the planet (JavaScript) is (used to be) strictly single-threaded. Async is all about keeping the CPU busy even though the stuff it does involves latencies thousands or millions of times longer than CPU timescales – and about abstractions that allow you to pretend you’re writing normal synchronous code when the reality is an…

> async doesn’t have much to do with mumticore

It does, once you have async you can multiplex n coroutines on m cpu cores, meaning you can throw libthread out of the window.

> C hasn’t been relevant on the web since 1995

Do you know nginx, a core web technology is written in C? Linux is also C. Don’t forget that at the end ov every web request are syscalls and hardware.

Re: A four year plan for async Rust

#229

Earlier quoted context omitted.

That’s part of it, but it is also important that rust be an embeddable language. Ideally you should be able to replace a small component of a larger C or C++ program with Rust. Having a big fat runtime you’ve got to include before running any rust code makes that pretty much a non-starter.

> Having a big fat runtime you’ve got to include before running any rust code makes that pretty much a non-starter. Just reasoning aloud here. That looks to be another similarity with green threads and async. Async also requires a big fat runtime that isn't part of the language. Instead you have to pick an async colour - such as tokio. That's pretty much what happens with green threads now. You have to pick a runtime…

Sort of! I think this flexibility (the coat of many colors) is why Rust didn't implement the whole runtime, just Futures, and those futures are as minimal as they can possibly be. The smallest possible executor for futures is really quite tiny, with no need for the complexity of tokio's work-stealing, multi-threaded scheduler and all that. So it leaves a lot of room for minimal executors like https://docs.rs/smol/latest/smol/, or for you to write your own, or even to build some kind of FFI to send futures across to C or C++

I do completely agree with you that it would be great for std to pull in more traits from `futures` and elsewhere to allow it to be easier to write code against different runtimes! I think part of the intent was to get Futures out, see how they get used, and then to go from there. Hopefully we're getting into the "go from there" stage now, which is some of what this article gets into

Re: A four year plan for async Rust

#230

Earlier quoted context omitted.

Rust had green threads prior to 1.0, and they were ripped out for performance and other reasons. Probably worth revisiting those discussions to see where this has been thought through by the Rust team

> Probably worth revisiting those discussions to see where this has been thought through by the Rust team The issue generated a lot of hot air at the time, far more than I have time to read, but I think I have the gist of it. The performance issues were due to an implementation choice. All green thread implementations I'm aware of hide the code colouring event driven I/O introduces, and Rust did the same. The hiding…

> That translates to every I/O call has at some point chose the blocking or non-blocking implementation.

Sometimes I feel like the only way to get really good async I/O is to rewrite the whole damn thing to use io_uring. Avoid the blocking syscalls as a whole.

("Rewrite" because this changes e.g. read buffer management. The fundamental APIs will have to change, to enable the performance gains.)

Post reply on HN