釘選
When you await a future, all local variables (that would ordinarily be stored on a stack frame) are instead stored in the Future for the current async block. If your future has pointers to data on the stack, those pointers might get invalidated. This is unsafe.
Therefore, you must guarantee that the addresses your future points to don’t change. That is why we need to pin
futures. Using the same future repeatedly in a select!
often leads to issues with pinned values.
Speaker Notes
-
You may recognize this as an example of the actor pattern. Actors typically call
select!
in a loop. -
This serves as a summation of a few of the previous lessons, so take your time with it.
-
Naively add a
_ = sleep(Duration::from_millis(100)) => { println!(..) }
to theselect!
. This will never execute. Why? -
Instead, add a
timeout_fut
containing that future outside of theloop
: -
This still doesn’t work. Follow the compiler errors, adding
&mut
to thetimeout_fut
in theselect!
to work around the move, then usingBox::pin
: -
This compiles, but once the timeout expires it is
Poll::Ready
on every iteration (a fused future would help with this). Update to resettimeout_fut
every time it expires.
-
-
Box allocates on the heap. In some cases,
std::pin::pin!
(only recently stabilized, with older code often usingtokio::pin!
) is also an option, but that is difficult to use for a future that is reassigned. -
Another alternative is to not use
pin
at all but spawn another task that will send to aoneshot
channel every 100ms.