5 ms·
> Isn't the state machine approach the same as C#/.net async/await is using ? But the with the added convenience of the syntactic sugar ? Similar in principle,
by pcwalton 10y ago
> Isn't the state machine approach the same as C#/.net async/await is using ? But the with the added convenience of the syntactic sugar ?
Similar in principle, but the implementation is different. Tasks in C# are more of an OO style instead of a FP style where they turn into an enum (sum type, if you want to get theoretical).
> 2 - no allocation : , does'nt the lambda closure need to be allocated somewhere ?
No, not in Rust (or in C++).
> from my understand the C++ approach is even more efficient in term of context switching and have the advantage of even less allocation.
No, you're asserting this without understanding Rust. It's not possible to get less than zero allocation.
- soulbadguy 10y agoYes , i only have a simple understanding of rust memory model . So what happened when/if the future escapes/outlives the current stack/context ?
- Rusky 10y agoThis is handled by the borrow checker, the same as anything else that might hold references to stack data - you get a compiler error and then can decide how to resolve the conflict, either by extending the lifetime of the referent (perhaps by boxing, or creating it earlier in the call stack), or by shrinking the lifetime of the future.
- steveklabnik 10y agoFrom the post > There are essentially no imposed synchronization costs; if you want > to associate data that lives on your event loop and access it in a > single-threaded way from futures, we give you the tools to do so.
- dbaupp 10y agoIt's an error if that would be unsafe, or else it compiles fine: the future compiles down to an enum/struct that stores everything inline and it can be returned/move up the stack/stored in global memory the same way that aggregate values returned without allocation (etc.) in C or C++.
- aturon 10y agoTo be clear, the issue here isn't so much stack vs heap, as much as how many heap allocations are happening. In practice, you build up a really big combined future on the stack, which has all of the space needed for any state in its state machine, and then when the future is fired off (in a task -- one per connection), that entire thing is moved into the heap in one shot. Thus, generally, you do one big allocation up front per connection -- exactly the same as you'd do when writing state machines by hand. The follow up posts will go into much more detail on this point :)
- soulbadguy 10y agoFair enough, but op was quite misleading by saying that in rust closure don't need allocation. So back to future vs coroutine , it seems that they the advantage in term of allocation simply because the context is not distroid when suspending/resuming coroutines
- steveklabnik 10y agolet mut counter = 0; let mut increment = || { counter += 1; counter }; increment(); increment(); There is no heap allocation there.
- saynsedit 10y agoThis is missing his point. "Increment" is called outside of its scope when the epoll triggers. If "counter" is stack allocated that would cause a segfault, so it must be heap allocated which is his point.
- steveklabnik 10y agoWell, they're two different points: closures in rust do not inherently have to heap allocate. But that also doesn't mean that they can _not_ be heap allocated either. And in this example, it's not even really the closures that allocate: it's still one allocation, regardless of the number of closures.
- eddyb 10y agoCompile error if it's holding on to any borrowed data on the stack - however, borrowing is only the default, if you move from a capture your closure will contain that value instead of reference to the value, and if you have "move" in front of your closure, all the captures are contained in the closure, so by boxing or by using -> impl Fn(...) you can safely return it. If you need to hold onto data accessed from multiple locations, you'd need to use Rc<T> instead of keeping that data on the stack, which is closer to GC'd languages (and pretty similar to Swift, IIUC, except Rust is more explicit).