3 ms·
Yes , i only have a simple understanding of rust memory model . So what happened when/if the future escapes/outlives the current stack/context ?
by soulbadguy 10y ago
Yes , 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.
- soulbadguy 10y agoNo. they are not two different points. You are artificially restricting the argument, and saying that some parts are a different question by introducing this new idea of "inherent nature" of a closure in rust : Some humans have legs, some do not. Does it mean that having legs is not an "inherent" part of the human experience? So to go back to the argument, we are trying to compare using a coroutine base approach vs using a future/state machine + closure approach. My point was that because a coroutine allows one to enter and leave a stack frame without destroying it, it can lead to less allocation and therefore be more efficient in those cases (and let's not even talk about the cost of the activation/deactivation of the stack frame)
- 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).