7 ms·
"The STL library lacks support for some modern programming tools, for example, native co-routine support. As a result, developers must rely on many community pr
by foxbee 4y ago
"The STL library lacks support for some modern programming tools, for example, native co-routine support. As a result, developers must rely on many community projects, and most lack long-term support."
I couldn't agree more with this comment. As great as the community is, there's a lot of projects that are just not maintained. I wish this was different.
- crabbone 4y agoRust doesn't have support for native co-routines. You rely on community project for that (Tokyo). At first I even thought it was an argument against Rust, not in favor...
- Tamschi 4y agoIt's "Tokio". Coroutines in Rust are a native language feature and their API is part of `std`, but the executors indeed come from community libraries. Tokio is one option, but as long as you don't contextually fork (for parallelism) you can in theory run the same coroutines on any other executor, like the ones from async-std. Spawning a sibling task (as opposed to mixed child task polling, which can be macroed inline) unfortunately isn't available through the common API so far, which is where the bulk of the mentioned incompatibilities stems from.
- RedPanda250 4y agoSorry if I'm missing something important as I have experience with C++ but not rust, but is async/await the right abstraction in Rust vs. the underlying generators which I assume is lower level and closer to C++20 Co-routines in terms of performance ? [1] In other words, it seems Rust co-routines at the level of Tokio are not as performant as C++ native Co-routines [2] and further down the thread, it's mentioned that once generators are stabilized, it might help build lower cost and performant stackless coroutines in Rust.[3] [1] https://github.com/rust-lang/rust/issues/43122#issuecomment-716871690 https://github.com/rust-lang/rust/issues/43122#issuecomment-... [2] https://github.com/rust-lang/rust/issues/43122#issuecomment-716256938 https://github.com/rust-lang/rust/issues/43122#issuecomment-... [3] https://github.com/rust-lang/rust/issues/43122#issuecomment-716263636 https://github.com/rust-lang/rust/issues/43122#issuecomment-...
- Tamschi 4y agoHmm… I'd say for IO-bound tasks/loading in a DBMS yes, async/await coroutines are the correct abstraction, since you're waiting to reschedule on external notice and normally don't want to spin-wait (or you could block on the optimistic case and then `.await` the fallback). If you'd like to do modular data processing instead then the current best Rust approach is using `Iterator`s[1] and possibly the `rayon`[2] crate for safe parallelisation. There currently is no coroutine feature that maps nicely onto `Iterator`s, or rather that's indeed expected to be the unstable generators feature, as it should cover that use case without overhead. (Async-coroutines map onto `Future`[3] instead.) You can think of Rust's `async` and generator use cases vaguely like the ones of JS's async and generator functions. The latter will function without any runtime or trampoline if you advance it in a loop, as far as I can tell, but they're unwieldy if what you want to yield on are only waits on external events. (`Waker`s[4] have similar consumer semantics to JS's or C#'s continuation passing, even if they are only indirect memory management handles.) It also often makes sense to use both of these at the same time to produce something like an `AsyncIterator`[5], but I expect that feature to be quite some ways away in Rust, at least in a seamlessly mixing fashion.[6] - - - I'm actually pretty curious which will turn out faster in practice between C++'s coroutines and Rust's generators, since their memory management is so different. The Rust coroutines (that is: including `Future`s) are generally stackless already, but also by default heapless, as their entire memory is abstracted as opaque instance with anonymous type that is returned to the caller by value. Boxing them is an explicit operation, and it's equally possible to pin them on the current stack/in the current instance instead. (That's how `.await` works; the child is embedded into the outer `Future` directly.) There are some pitfalls related to this, since that instance's size is determined by the largest `.await`/yield site, but the tooling should (eventually) be able to warn on unexpectedly large `.await`/yield locations like it currently warns on unexpectedly large enum variants.[7] (I'll borrow your footnote style.) [1] https://doc.rust-lang.org/stable/core/iter/trait.Iterator.html https://doc.rust-lang.org/stable/core/iter/trait.Iterator.ht... [2] https://crates.io/crates/rayon https://crates.io/crates/rayon [3] https://doc.rust-lang.org/stable/core/future/trait.Future.html https://doc.rust-lang.org/stable/core/future/trait.Future.ht... [4] https://doc.rust-lang.org/stable/core/task/struct.Waker.html https://doc.rust-lang.org/stable/core/task/struct.Waker.html [5] https://doc.rust-lang.org/stable/core/async_iter/trait.AsyncIterator.html https://doc.rust-lang.org/stable/core/async_iter/trait.Async... [6] then comparable to JS, I'd assume, where `yield` and `await` aren't necessarily paired: <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...> [7] https://rust-lang.github.io/rust-clippy/stable/index.html#large_enum_variant https://rust-lang.github.io/rust-clippy/stable/index.html#la...
- planede 4y agoBoost ASIO has some coroutine support. I would not call it a hobby project either.
- gpderetta 4y agoIndeed. Also seastar comes with coroutine supports[1], and incidentally it was written for a very high performance C++ database implementation. [1] https://docs.seastar.io/master/split/5.html https://docs.seastar.io/master/split/5.html
- lionkor 4y agoC++20 comes with coroutines, no?
- deleted 4y ago[deleted]
- Tamschi 4y agoThey aren't strictly comparable. While the heap allocation may be optimised out, there is no way to use native C++ coroutines as guaranteed zero-cost construct due to the automatic heap allocation in the API. Rust's coroutines currently have practical optimisation issues related to instance size (because the compiler isn't smart enough yet in a few places), and the more powerful generator API very much isn't ready yet, but they give you considerably more control over the memory management. It's easy to stack- or pool-allocate coroutines there if necessary for performance, while in C++ you wouldn't be able to use the native language feature where frequent or unmonitored heap allocations from fine-grained coroutine use would be a problem. (Apparently this makes them unsuitable for AAA game development, for example.) Library-provided coroutines may be more versatile.
- andreidd 4y agoNot entirely true. You can pool allocate a C++ coro.
- Tamschi 4y agoAh, you're right, I missed it because it's callee-controlled in C++. (See Heap Allocation and Promise on https://en.cppreference.com/w/cpp/language/coroutines https://en.cppreference.com/w/cpp/language/coroutines , for those curious.) Rust coroutines evaluate to opaque value types instead of handles, for comparison, so the caller gets to decide what to do with them. Currently they're a bit unwieldy though, until naming (aliasing) their types becomes possible. The unstable documentation for that is here: https://rust-lang.github.io/impl-trait-initiative/explainer/tait.html https://rust-lang.github.io/impl-trait-initiative/explainer/... (Edit: Sorry, I'd grabbed the wrong second link. Fixed.)
- menaerus 4y agoCo-routines are available in C++20. And in dozens of other libraries, if for some reason OP is limited to < C++20 which I doubt considering that the product is not yet launched.
- secondcoming 4y agoProjects going stale is a cross-language problem really. Rust will also encounter this at some point.
- bregma 4y agoNo, because they'll just rewrite them in the latest Rust.