Asynchronous 在实践中实现未来时如何使用上下文和唤醒器

Asynchronous 在实践中实现未来时如何使用上下文和唤醒器,asynchronous,rust,rust-tokio,Asynchronous,Rust,Rust Tokio,我发现很难理解为什么以及何时需要显式地对传递给poll方法的Future对象执行上下文和/或其Waker执行操作。我一直在阅读和的文档,但我觉得示例/方法过于抽象,无法应用于实际问题 例如,我本以为下面的MRE会死锁,因为新的\u内部\u任务生成的未来将不知道消息何时在MPSC通道上传递,但是,这个示例似乎工作正常。为什么会这样 使用std:{future::future,pin::pin,task:{Context,Poll},time::Duration}; 使用未来:{futurext,S

我发现很难理解为什么以及何时需要显式地对传递给
poll
方法的
Future
对象执行
上下文和/或其
Waker
执行操作。我一直在阅读和的文档,但我觉得示例/方法过于抽象,无法应用于实际问题

例如,我本以为下面的MRE会死锁,因为
新的\u内部\u任务
生成的未来将不知道消息何时在MPSC通道上传递,但是,这个示例似乎工作正常。为什么会这样

使用std:{future::future,pin::pin,task:{Context,Poll},time::Duration};
使用未来:{futurext,StreamExt};//0.3
使用东京::同步::mpsc;//1.2
使用tokio_stream::wrappers::UnboundedReceiverStream;//0.1
异步fn新的内部任务(rx:mpsc::UnboundedReceiver){
让mut requests=unboundereceiverstream::new(rx);
而让一些()=请求。下一步()等待{
eprintln!(“收到的请求”);
}
}
pub-struct-ActiveObject(Pin);
impl-ActiveObject{
pub fn new()->(Self,mpsc::UnboundedSender){
let(tx,rx)=mpsc::无界_信道();
(Self(新的内部任务(rx).boxed()),tx)
}
}
ActiveObject的impl未来{
类型输出=();

fn poll(self:Pin,cx:&mut Context您正在将相同的
上下文
(以及
Waker
)传递给
new_internal_task
返回的未来的
poll()
方法,该方法将其沿着链传递给
unboundereceivestream::next()返回的
未来的
poll()
。它的实现安排在适当的时间(当频道中出现新元素时)在此
Waker上调用
wake()
。完成后,东京轮询与此
Waker
相关的顶级未来-三个未来中的
join!()


如果您省略了轮询内部任务的那一行,而只是返回了
Poll::Pending
,那么您将得到预期的情况,即您的
未来
将被轮询一次,然后“挂起”永远,因为没有什么会再次唤醒它。

东京提供的实用程序显然已经可用,它们与反应堆/执行器本身交互。你可以构建新的未来(这也是你使用异步函数所做的)基于它们的组合,这就是你的
ActiveObject
所做的。如果你的实现不以现有的未来为基础,例如在抽象操作系统调用时,你只需要深入了解细节。你能补充一下为什么
ActiveObject
会被轮询两次(而不是一次)吗在第一个元素进入通道之后,但在第二个元素进入通道之前?看一下,它似乎在期货中共享单一的
上下文
,并将在每次醒来时轮询每个期货(
obj
ds
ds2
)。因此它是这样的:1.初始
poll()
;2.
poll()
sleep()
之后发生
send()
并打印“发送请求”,等等。
[polled]
[polled]
sent request
[polled]
received request
[polled]
sent request
[polled]
received request