-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
Add conversion from Arc<Fn> to Waker #70764
Conversation
r? @sfackler (rust_highfive has picked a reviewer for you, use r? to override) |
The point I meant to make was actually a bit different: that the safe Wake trait could be a better alternative to converting from closures. I wonder if you could elaborate on what you see as the advantages of a closure-conversion API in contrast to using the Wake trait? I'll write about how I understand the trade off. First, a real-world example of a waker - block_on implemented on top of crossbeam Unparker: // With the Wake trait
use std::task::{Waker, Wake};
use crossbeam::sync::{Unparker};
struct BlockOnWaker {
unparker: Unparker,
}
impl Wake for BlockOnWaker {
fn wake(self: Arc<Self>) {
self.unparker.unpark();
}
}
fn block_on<F: Future>(future: F) -> F::Output {
let unparker = ...;
let waker = Waker::from(Arc::new(BlockOnWaker { unparker }));
...
} // With this API
use std::task::Waker;
fn block_on<F: Future>(future: F) -> F::Output {
let unparker = ...;
let waker = Waker::from(Arc::new(move || unparker.unpark()));
...
} Certainly this API is briefer! Indeed, that's the advantage of the closure-based API that's obvious to me: it allows you to write a waker in only a few lines of code, without the "ceremony" of defining a new type and implementing Wake for it. But I think that the ceremony is actually quite valuable, and I'm not convinced we should endorse an alternative which eliminates it:
So I would say this bit of ceremony is advantageous for everyone, and only really costs points in code golf scenarios where users are showing off executor systems built in 12 lines of code and so on. From my perspective, it doesn't seem worthwhile to promote this ellison to std. |
@withoutboats thanks for taking your time to reply in full. Looks like I indeed misunderstood what you said. I don't disagree with any of the points you've laid out and trust your ability to assess the value this conversion has. I guess the only thing I neither of us has touched on so far is this method as a means of teaching folks about futures: this shows a |
This maybe has to do with our different backgrounds: having worked in pretty OOP-oriented languages before Rust, and not any language which is callback-heavy (ie not pre-ES2015 JS) I find "an object which has a wake method" a much more grokable explanation of what a waker is than "a thread-safe callback." |
This is an addition to work done in #68700. This patch adds a conversion from
Arc<Fn>
toWaker
making it significantly easier to construct wakers for instrumentation purposes.The conversion of a closure into a waker has seen prior adoption in the ecosystem in the form of the
wakeful
crate by @sagebind. And was later adopted by @stjepang inasync-task
as well.Usage
Alternatives
Originally there was talk about adding a
task::waker_fn
instead. But @withoutboats pointed out there had always been an intention to add a safeWake
trait, and conversions from closures could instead utilize that. Now thatWake
is available on nightly, it seemed like a good idea to implement this conversion as well.While drafting this patch I also tried to make a non-arc conversion work, but unfortunately failed because of orphan rules (
Waker
andFn
are defined incore
,Arc
is defined inalloc
):I'm not sure if there is a way around that given that tests wouldn't compile if this was a problem. But if that's not desirable for any reason, we should probably review this conversion is forward-compatible with a future conversion from
From<Fn() + Sync + Send + 'static> for Waker
.Stability
I think this conversion should be separate from the core trait introduced in #68700. Any issues that might arise from this should not hold up the stabilization of the core trait; so I propose we track this (and any future conversions) separately.
References
wakeful::waker_fn
async-task::waker_fn
Wake
trait