我正在尝试了解 Async Rust Future 中轮询的工作原理。使用下面的代码,我尝试运行两个 futures Fut0
和 Fut1
,这样它们交错如下 Fut0 -> Fut1 -> Fut0 -> Fut0
.
extern crate futures; // 0.3.1
use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll, Waker};
use std::cell::RefCell;
use std::rc::Rc;
use std::collections::HashMap;
use futures::executor::block_on;
use futures::future::join_all;
#[derive(Default, Debug)]
struct Fut {
id: usize,
step: usize,
wakers: Rc<RefCell<HashMap<usize, Waker>>>,
}
impl Future for Fut {
type Output = ();
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
self.step += 1;
println!("Fut{} at step {}", self.id, self.step);
{
let mut wakers = self.wakers.borrow_mut();
wakers.insert(self.id, cx.waker().clone());
}
{
let next_id = (self.id + self.step) % 2;
let wakers = self.wakers.borrow();
if let Some(w) = wakers.get(&next_id) {
println!("Waking up Fut{} from Fut{}", next_id, self.id);
w.wake_by_ref();
}
}
if self.step > 1 {
Poll::Ready(())
} else {
Poll::Pending
}
}
}
macro_rules! create_fut {
($i:ident, $e:expr, $w:expr) => (
let $i = Fut {
id: $e,
step: 0,
wakers: $w.clone(),
};
)
}
fn main() {
let wakers = Rc::new(RefCell::new(HashMap::new()));
create_fut!(fut0, 0, wakers);
create_fut!(fut1, 1, wakers);
block_on(join_all(vec![fut0, fut1]));
}
但它们总是以循环方式进行轮询,即 Fut0 -> Fut1 -> Fut0 -> Fut1 -> ...
。
Fut0 at step 1
Fut1 at step 1
Waking up Fut0 from Fut1
Fut0 at step 2
Waking up Fut0 from Fut0
Fut1 at step 2
Waking up Fut1 from Fut1
看起来,它们所有的 Context 都是相同的,因此每个 Futures 的 Wakers 也是相同的。所以唤醒其中一个也会唤醒另一个。是否可以为每个 future 设置不同的 Context(或 Waker)?
最佳答案
方法 futures::future::join_all
返回一个 future ,它按顺序而不是并行地轮询给定的 future 。你应该看待它的方式是, future 是嵌套的,执行者只会引用最顶层的 future (在本例中为 futures::future::join_all
返回的 future )。
这意味着当 join_all future 被轮询时,它将上下文传递给它当前正在执行的嵌套 future 。此后 join_all future 将把它传递给下一个嵌套的 future 等等。有效地为所有嵌套的 future 使用相同的上下文。这可以通过查看 JoinAll
future 的源代码来验证。在 future 箱子里。
block_on
executor 一次只能执行一个 future。使用线程池的执行器(例如 tokio)实际上可以并行执行 future ,因此将为不同的预定 future 使用不同的上下文(但由于上述原因,对于 JoinAll future 仍然是相同的上下文)。
关于rust - Async Rust 中每个 Future 的不同 Context 或 Waker,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58995888/