4 ms·
With respect to Rust, a big part of the issue here is that Rust is roughly attempting to turn Javascript into a systems programming language. While `async` as
by pclmulqdq 3y ago
With respect to Rust, a big part of the issue here is that Rust is roughly attempting to turn Javascript into a systems programming language. While `async` as a language feature is a key part of the ideas of JS, it's essentially fundamentally incompatible with 0-overhead systems programming (despite most systems programming using asynchronous concepts).
Asynchronous systems code is usually done completely stackless, using state machines and queues of objects, and batched functions that run to completion to transition objects to the next state. This gives you maximum cache-friendliness, and since good performance fundamentally comes from limiting your options, making unbounded state growth hard is a pretty good way to get it. Async functions with stacks are already a performance compromise in comparison. You can do this type of programming in Rust by just not using async.
Unfortunately, some fraction of Rust maintainers are pulling back towards Rust being a web backend language (see the earlier comment about Javascript), and that really needs a concept of stackful async, but really doesn't need the same level of performance as a kernel or a filesystem. Rust green threads would even have worked really well for this use case, despite being a huge mismatch with traditional systems programming. In addition, those async functions need some sort of runtime anyway, so it's not even really a standalone language feature distinct from the packages that enable it.
So here we are, in a situation around async that makes nobody happy. C++ coroutines, despite the hate they get, and Go green threads, despite the performance, actually seem to be closer to the mark.
- iknowstuff 3y agoRust async is stackless. While it's not as seamless as javascript yet, it too started with generators and janky promise libraries before - a decade later - support for it became ubiquitous. Rust will undergo a similar journey where the compiler will continually make improvements to ease of use, arriving at a very elegant solution that's just as easy to use.
- pclmulqdq 3y agoI'm pretty sure Rust people invented a new meaning for the word "stackless": in Rust's context it means "does not depend on an underlying architectural stack." It does not mean "does not use the concept of a stack." That would be why you can have stack traces of async functions in Rust. In practice it means allocating a stack for your function of the maximum size you would need.
- vacuity 3y agoRust didn't invent the terminology. Rust has stackless coroutines. Go has stackful coroutines. The literal distinction is that stackless coroutines exist independently of a stack: you have a state machine object that, when it's resumed into, is put onto the stack and calls normal functions through the run-time stack. Stackful coroutines are essentially lightweight threads (hence "green threads" or "virtual threads"): the coroutine comes with a miniature run-time stack. In practice, stackless coroutines are more space efficient and have lower context-switch costs. A big factor for Rust specifically is interoperating with C. Stackful coroutines make writing "straight-line" code simpler (no function coloring) but introduce more overhead.
- withoutboats3 3y agoasync is just a syntactic sugar to transform a function into the state machine you would have otherwise written. If you don't trust the compiler to perform this transform adequately, you can write a Future by hand. There are users using async/await syntax to write software for microcontrollers without dynamic memory allocation, runtimes like tokio are not a hard dependency of async/await syntax or the Future abstraction. C++ coroutines perform the same transform, but they dynamically allocate that state machine for every coroutine (unless the optimizer can eliminate the allocation). In contrast, Rust inlines every coroutine into a single state machine until you explicitly tell it to allocate it. I don't know why C++ chose a less "zero cost" solution; I suspect the fact that they don't have memory safety and so letting you own a coroutine's state is very footgunny in C++ played a part in their choice.
- xpe 3y ago> So here we are, in a situation around async that makes nobody happy. C++ coroutines, despite the hate they get, and Go green threads, despite the performance, actually seem to be closer to the mark. The story that gets told -- and for some reason, I tend to believe it, even though I'm much less idealistic than 10 years ago -- is that folks in the Rust community (and not just them of course, also C++ people and lots of others) tend to really push hard against abstractions that aren't both ergonomic and zero-cost. It is frankly kind of amazing to see the solutions that emerge after months and years of what somewhere resembles either head-butting or crazy experimentation. The path to getting there is messy, and it seems like maybe that's where we are now.
- ameliaquining 3y agoCan you explain what makes C++ coroutines work better than Rust futures?
- deleted 3y ago[deleted]