5 ms·
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 h
by mplanchard 3y ago
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
- rstuart4133 3y ago> 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 has to be done at run time. That translates to every I/O call has at some point chose the blocking or non-blocking implementation. This is typically done using vtables (dyn in Rust), but whatever mechanism is used, it introduces runtime overhead. Worse, it slows down everything - including code that doesn't use green threads. It gets radically worse if you try to hide C calls blocking. Async has the same issue, some solves it by making coloured code the programmers problem. If they had of made the same design decision for green threads the performance issues go away. We don't have to speculate about that. There is a green thread crate out there called "may", then has independent benchmarks covering it, async Rust implementations, and other languages. "may" beat everything at one point, but it's a very noisy benchmark so the only conclusion I would draw from it is that "may" looks to run at the same speed as async. As for the rest of the issues: they revolve around needing a separate stack. I tried to cover the trade-offs above. Summarising: green threads lead to simpler code that's easier to write and theoretically could run faster than async, but have larger setup overhead and use more memory.
- mplanchard 3y agoThat’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.
- rstuart4133 3y ago> 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.
- mplanchard 3y agoSort 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/ 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
- yencabulator 3y ago> 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.)