-
Notifications
You must be signed in to change notification settings - Fork 37
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Drop behavior for StopIf #76
Comments
It does drop the underlying Signal. When That tells the downstream consumer that it can safely Drop the Signal, because the Signal will never change. Dynamic methods like rust-signals/src/signal/signal.rs Line 1611 in 2a91d9c
rust-signals/src/signal/signal.rs Line 1623 in 2a91d9c
The In order to understand it, you first need to understand how Rust implements Futures: http://aturon.github.io/blog/2016/09/07/futures-design/ That article is a little outdated, but the concepts are still correct. Rust automatically inlines structs and methods. So let's say you create a chain of various Signal methods: some_signal
.map(...)
.filter(...)
.dedupe()
.for_each(...) Each one of those methods returns a struct, which contains the internal state that the method needs. Rust will create a single giant struct which combines all of those structs together. And all of the methods are inlined into a single giant method. This is excellent for performance, since there's no boxing or indirection, it just runs the code directly, and the code can access the struct state directly. However, that giant struct is allocated onto the stack, which won't work for asynchronous stuff like Signal/Stream/Future. So we have to When you use a Future executor like This means that the entire chain of methods only needs 1 box allocation when it's spawned and 1 box deallocation when it's finished, which is wicked fast for performance. When you use the This is how the Future/Stream/Signal system is designed: the Future/Stream/Signal returns |
Thank you for the detailed explanation! I also appreciate the answers that you have given in other issues, they are very helpful for learning how to use this crate. I can see that the underlying signals are dropped as soon as they have polled as completed in Because these behaviors are different, they could easily trip up users trying to implement custom signal adapters, especially if any of the signals involved have custom drop logic. One might expect from eg. In any case, the different drop behaviors should be explicitly documented. There are some signal adapters for which I am still uncertain of drop behavior due to implementation via macros, eg. |
That is the responsibility of the combinator method. The Future/Signal system guarantees that everything will get dropped properly, so if it's not dropping properly then that's a bug that needs to be fixed. Could you explain more about your use case and how you're using
I'm not sure what you mean by "adapter", but every Signal is dropped as soon as the downstream consumer is dropped (which can happen explicitly, or implicitly when the entire task is dropped). In general it's very very very hard to accidentally leak memory, and you don't need to worry about it: the memory is managed automatically. If you are writing your own Signal combinator, then yes you need to be aware of various internal details (including the Signal contract). You need to understand how the methods combine in a zero-cost way (with struct inlining). You need to understand how Future tasks are allocated and deallocated, and it's very helpful to understand how Future executors work internally. Creating your own Signal combinators is very much so expert-only, it's not something that regular users should need to worry about: you can just call the existing combinator methods and everything should work correctly. |
StopIf
should drop the underlying signal once the stop condition is fulfilled, instead of just not polling it any more.The text was updated successfully, but these errors were encountered: