-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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
Future-proof the Futures API #59119
Future-proof the Futures API #59119
Conversation
The job Click to expand the log.
I'm a bot! I can only do what humans tell me to, so if this was not helpful or you have suggestions for improvements, please ping or otherwise contact |
In terms of the list of possible extensions this is intended to be forward compatible with, I would divide them into two groups:
I'd like to be confident our API is sufficient for supporting the former, and rule out the idea that the argument passed to future is the correct way to pass the latter (I see this argument, currently called waker, as strictly a way to interact with the executor this future is being executed on). So I would like to see task locals properly explored to see what would need to change about the current API. I am not really in favor of adding this indirection, because I think we should not pass context unrelated to the executor through this interface. In terms of compatibility I'm much more concerned about ending up with a very unwieldly construction API for |
Meta-question: why is this a PR rather than an RFC? It seems to be a significant departure of the Futures API design accepted in rust-lang/rfcs#2592. There isn't consensus yet on this API modification. And maybe it's just me, but by opening a PR directly on stdlib instead of going through the RFC process I feel unnecessary urgency (and tension) is added to the decision making process. |
I don't agree. I'd like that we didn't rule it out so early. Other languages have shown it to be useful, and we don't have experience to the contrary in Rust. Forwards-compatibility is not something libstd should rule out quickly. In comparison, ergonomics of creating a waker is not something I would optimize for. Regular users will never have to create one. Only a couple executor libraries will.
It was a question brought up multiple times in the RFC, but never really addressed. The tracking issue mentioned it as an unresolved question. As for why it's a PR already, it might be slightly early. 🤷 |
I consider the task-locals discussion to have been settled on the RFC thread. As for whether or not to provide executors this way, adding any additional data like this to the |
Only if the |
The future-proofing was left as an open-question during FCP. We will still require an FCP for stabilization which cover all final amendments that have been made to the API. I don't personally view this as a significant digression from the API suggested there, as the only functional change is to move |
(From a procedural point-of-view, I think that discussing this point in a PR is reasonable. As @cramertj says, we often make amendments to details from the RFC during the implementation period, particularly when addressing unresolved questions.) |
Yup! I agree. |
I'll try reiterating the core arguments of both sides. Please correct me if my understanding is wrong. The argument in favor of
|
@stjepang that does not reflect my argument. My argument is that we should not block stabilizing Future on exploring all possibilities of the future api to an extent that we can comfortably say “this is it, we will never have to change this ever again”. My examples are simply illustrations of thibgs that could be possible. The fact is that hardly any of the ecosystem has switched to using explicit waker. Once there is more usage who is to say what other use cases will come up. I came up with possibilities as a straw man. Of course the ecosystem won’t start moving until the api is stable, so it is a chicken / egg problem. The proposal for context is to allow changes to the api in the future as cases come up instead of locking the api down now to potential future changes. Focusing on the specific example is missing the point. |
@carllerche Thanks for clarifying! Do you think it is possible a use case will come up which cannot be satisfied through other means like TLS or global statics? It seems spawners, reactors, timers, and task locals can be accessed through TLS just fine. (Even wakers could be accessed through TLS but there are valid reasons to pass them as arguments instead.) Or did you mean we might want |
@stjepang I cannot say for sure as I have not spent the time investigating. This is my point. One issue is going to be FuturesUnordered. This type alters the waker. How would this interact with any task local state set via thread locals? Also, I have had cases where I wanted a fresh task context while polling (using Spawn in 0.1). I don’t know how this would apply. Regardless of this, I’m pretty sure they using the context argument would be noticeably faster than thread locals. So, not future proofing would give up these potential improvements. |
|
I see the problem with task local state, but don't see how putting additional data into
Sorry, I don't follow. The futures 0.1 crate doesn't have
That is true, but is similar to the argument against the RFC proposing to merge That is not to say you're not raising fair points - I appreciate the concerns around stabilizing |
Hello, async world. This thread seems to be have slowed down, which is good. I wanted to add a link to an experiment that I am trying here. Below is a Dropbox paper document containing my best effort at a summary of the pros/cons for this change: This is based on me skimming the thread here as well as some of the other threads, along with some conversation with @cramertj, @yoshuawuyts, and @withoutboats. I am posting it here because I would like to encourage others to take a look and offer suggestions -- especially @carllerche, as a strong advocate of this PR. I included some directions in the document, but the idea is that this to be a collaboratively produced summary that captures the major points. To that end, my hope is that -- if you leave a comment -- you can offer alternate wording that takes an existing point and makes it more precise (or perhaps adds details). I will either adopt that wording or try to incorporate it into the main text. I do plan to use editorial discretion to keep this concise, but I don't honestly have a very strong opinion about this particular PR, so I aim to be unbiased. Please let me know if you feel I am not (ideally over privmsg, so we can chat). ❤️ I know we are all eager to see the |
To clarify, I think that the decisions re: |
I just wanted to add to the discussion that using async functions it is possible to provide a context (or any argument) without changing the async fn my_future(ctx: Context) -> () {
println!("Context field: {}", ctx.field);
()
} This leave the |
@Thomasdezeeuw that'd be more like call context. This PR is about execution context. Things that you may not know at the call site (similar to how we don't know what the waker is yet). |
@nikomatsakis My primary argument is stronger than "In short, we cannot know the future." It is: "There are things we know about now that are worth exploring, but lets not hold up stabilization to do so." I have explicitly avoided to argue for any of these potential improvements so far in an effort to focus on stabilization. To be honest, I did not expect the forwards compatibility proposal to be controversial. If it is rejected, then we will need to front load evaluating these changes. |
OK. Thanks for that. I have attempted to rework the introduction in a way that I think captures what you wrote here:
If that's not quite right, please supply an edit that works better. =) |
I spent a good hour yesterday going over the document, trying to resolve comments. There are still a few comments left that I wasn't able to incorporate, but I think overall it's fairly representative. Still, the document is quite long by now. From reading it, I think the crux of the debate comes down to TLS. So let me take a shot at pulling out the "core tradeoff". I'm curious to hear what people think. Let me know if you don't feel represented here =) The tradeoff
So the core tradeoff here is this:
Note that I emphasized passing implicit parameters. By this I mean data passed from the caller of The conclusionSo, which way you fall will depend on
I think a number of people feel that, by now, between Rust and other ecosystems, we have a pretty good handle on what sort of data we want to thread around and what the best way is to do it. Further, they feel that TLS or passing parameters explicitly is the best solution approach for those cases. Therefore, they prefer to leave the design as is, and keep things simple. (More details in the doc, of course.) Others, however, feel like there is additional data they want to pass implicitly and they do not feel convinced that TLS is the best choice, and that this concern outweights the ergonomic costs. Therefore, they would rather adopt the PR and keep our options open. Finally, I think there is a third position that says that this controversy just isn't that important. The performance hit of TLS, if you wind up using it, seems to be minimal. Similarly, the clarity/ergonomics of Footnotes* -- One caveat is that there is another option besides TLS. We could add add'l state to the Waker. The document dives into the tradeoffs there. My opinion is that it seems to be (overall) a less appealing option than TLS, and certainly a less explored one in practice, so I chose to leave it off. |
The job Click to expand the log.
I'm a bot! I can only do what humans tell me to, so if this was not helpful or you have suggestions for improvements, please ping or otherwise contact |
@bors r- Failed the miri UI test |
Should we temporarily ignore that Miri test (maybe as part of #59755 if we are quick enough)? Else we wait until the beta branched and tool breakage is a thing again. |
MIRI has been updated @bors r=withoutboats |
📌 Commit 1691e06 has been approved by |
Future-proof the Futures API cc #59113, @carllerche, @rust-lang/libs r? @withoutboats
☀️ Test successful - checks-travis, status-appveyor |
Final (one can only hope) futures_api adjustments Based on rust-lang#59119 -- this change is only the latter two commits. cc rust-lang#59725 r? @withoutboats
Final (one can only hope) futures_api adjustments Based on #59119 -- this change is only the latter two commits. cc #59725 r? @withoutboats
Stabilize futures_api cc rust-lang#59725. Based on rust-lang#59733 and rust-lang#59119 -- only the last two commits here are relevant. r? @withoutboats , @oli-obk for the introduction of `rustc_allow_const_fn_ptr`.
Stabilize futures_api cc rust-lang#59725. Based on rust-lang#59733 and rust-lang#59119 -- only the last two commits here are relevant. r? @withoutboats , @oli-obk for the introduction of `rustc_allow_const_fn_ptr`.
Stabilize futures_api cc rust-lang#59725. Based on rust-lang#59733 and rust-lang#59119 -- only the last two commits here are relevant. r? @withoutboats , @oli-obk for the introduction of `rustc_allow_const_fn_ptr`.
Stabilize futures_api cc rust-lang#59725. Based on rust-lang#59733 and rust-lang#59119 -- only the last two commits here are relevant. r? @withoutboats , @oli-obk for the introduction of `rustc_allow_const_fn_ptr`.
cc #59113, @carllerche, @rust-lang/libs
r? @withoutboats