-
Notifications
You must be signed in to change notification settings - Fork 13.7k
Description
The Futures Waker
API provides a Waker::will_wake() method which tries to determine whether the 2 Waker
s are equivalent. It intends to allow Future
s so determine whether they have to swap a Waker
or have to can keep an already stored one which is equivalent. That can avoid some churn on atomic refcounts on those Waker
s.
The will_wake
method is implemented by a PartialEq
derive on RawWaker
- which means will_wake()
will return true
only if the pointer as well as the vtable in RawWaker
are equivalent.
However futures executors are moving more and more towards a design where they lazily create the "real" storeable Waker
, and only provide a Waker
reference to tasks they poll. E.g. futures-rs
uses WakerRef tokio does the same. This avoids an atomic increment and decrement cycle for each task that an executor polls.
However this means the RawWaker
that the executor passes through the Context
parameter will now always be different to the one stored inside a Future
and will_wake()
will return false. Which causes the Future
to update the Waker
reference (2 atomic ops). If the executor polls a couple of sub-tasks which now all swap out their Waker
s the original executor optimization could now even lead to de-optimization - since the result is more atomic ops in other places.
Using the will_wake()
method makes most sense exactly inside the .poll()
method of a Future
in order to determine whether a stored Waker
needs to get updated. This is now the exact same point where the WakerRef
would return the false negative. Therefore using .will_wake()
is not that helpful given the state of the executor ecosystem.
So far for the description of the issue. The next question is whether this can be improved or solved. I don't think changing PartialEq for RawWaker
- e.g. to conly compare the data pointer - makes sense. It will likely only lead to false positives (waker.will_wake(other) == true
). Which then leads to missing wakeups aka live-locks.
The original design of RawWaker
plus Vtable
contained a vtable entry for will_wake()
. This would have definitely helped to solve the issue, since the executors would have been able to overwrite the check and to be able to associate Waker
s and their WakerRef
s. However this was removed for simplification purposes.
I think one possible outcome could be to keep this issue as a tracking issue for the deficit. And if there is ever a change to the vtable for other reasons to also add a will_wake
method back. Up to then it's probably not worth an update.