在轮询时唤醒 Rust 未来是否有效?
Is it valid to wake a Rust future while it's being polled?
我希望能够为一个人睡我的未来 "frame" 以便可以进行其他工作。这是这个想法的有效实施吗?
use std::future::Future;
use std::task::{Context, Poll};
use std::pin::Pin;
struct Yield {
yielded: bool,
}
impl Future for Yield {
type Output = ();
fn poll(mut self: Pin<&mut Self>, ctx: &mut Context) -> Poll<()> {
if self.yielded {
Poll::Ready(())
} else {
self.yielded = true;
// This is the part I'm concerned about
ctx.waker().wake_by_ref();
Poll::Pending
}
}
}
具体来说,我担心的是,如果上下文在轮询 returns Pending
之前进行,则不会 "notice" wake_by_ref
调用。 poll
的接口契约是否保证以这种方式执行此任务时会立即重新轮询?
TL;DR:您的代码有效。
根据唤醒者的合约,它必须再轮询一次你的未来。否则,可能会在 Future::poll
调用与实际执行某些工作的 future 对应方之间出现竞争条件。
我们来看一个例子:
impl Future for Foo {
type Output = ();
fn poll(self: Pin<&mut Self>, ctx: &mut Context) -> Poll<()> {
let result = communicate_with_worker(ctx); // returns false
// <-- Time point (1)
return match result {
true => Poll::Pending,
false => Poll::Ready(()),
};
}
}
在时间点(1),future已经决定它还没有准备好,但是有可能这里polling线程暂停了,worker线程被调度完成了它的工作。
然后工作线程将调用唤醒器并请求再次轮询未来。如果唤醒者决定不再轮询未来,因为它现在正在轮询未来,那么唤醒者将永远不会再次收到唤醒请求。
这意味着唤醒器可能会丢弃之前的唤醒请求
poll
被调用,但不允许丢弃唤醒请求
在未来的 poll
通话中出现。
我唯一的问题是:您为什么要重新安排多一帧的轮询?
由于您的实际工作必须在单独的线程中完成(而不是在 fn poll
中),因此重新安排轮询没有任何意义。
我希望能够为一个人睡我的未来 "frame" 以便可以进行其他工作。这是这个想法的有效实施吗?
use std::future::Future;
use std::task::{Context, Poll};
use std::pin::Pin;
struct Yield {
yielded: bool,
}
impl Future for Yield {
type Output = ();
fn poll(mut self: Pin<&mut Self>, ctx: &mut Context) -> Poll<()> {
if self.yielded {
Poll::Ready(())
} else {
self.yielded = true;
// This is the part I'm concerned about
ctx.waker().wake_by_ref();
Poll::Pending
}
}
}
具体来说,我担心的是,如果上下文在轮询 returns Pending
之前进行,则不会 "notice" wake_by_ref
调用。 poll
的接口契约是否保证以这种方式执行此任务时会立即重新轮询?
TL;DR:您的代码有效。
根据唤醒者的合约,它必须再轮询一次你的未来。否则,可能会在 Future::poll
调用与实际执行某些工作的 future 对应方之间出现竞争条件。
我们来看一个例子:
impl Future for Foo {
type Output = ();
fn poll(self: Pin<&mut Self>, ctx: &mut Context) -> Poll<()> {
let result = communicate_with_worker(ctx); // returns false
// <-- Time point (1)
return match result {
true => Poll::Pending,
false => Poll::Ready(()),
};
}
}
在时间点(1),future已经决定它还没有准备好,但是有可能这里polling线程暂停了,worker线程被调度完成了它的工作。
然后工作线程将调用唤醒器并请求再次轮询未来。如果唤醒者决定不再轮询未来,因为它现在正在轮询未来,那么唤醒者将永远不会再次收到唤醒请求。
这意味着唤醒器可能会丢弃之前的唤醒请求
poll
被调用,但不允许丢弃唤醒请求
在未来的 poll
通话中出现。
我唯一的问题是:您为什么要重新安排多一帧的轮询?
由于您的实际工作必须在单独的线程中完成(而不是在 fn poll
中),因此重新安排轮询没有任何意义。