问题描述
是否有可能,如果一个任务发送到a
,而另一个(同时)发送到b
,则tokio::select!
和{{1 }}通过取消剩余的将来值来丢弃其中之一?还是可以保证在下一次循环迭代时收到?
a
在这种情况下,我的头脑无法绕开b
魔术背后真正发生的事情。
解决方法
在任何地方的文档中似乎都无法保证,但是由于生锈的基于轮询的体系结构,这种方法很可能直接从通道读取。选择等同于以随机顺序轮询每个期货,直到其中一个就绪,或者如果没有,则等待直到发出唤醒信号,然后重复该过程。仅当成功轮询返回时,消息才会从通道中删除。成功的轮询将停止选择,因此其余通道将不会被触及。因此,下次循环发生时将对它们进行轮询,然后返回消息。
但是,这是一种危险的方法,因为如果将接收方替换为返回期货的东西,而该期货执行的操作比直接读取更复杂,则读取后可能会挂起,那么当发生读取之后,您可能会丢失消息。因此,应该将其视为无效。一种更安全的方法是将期货存储在触发时更新的可变变量中:
use tokio::sync::mpsc::Receiver;
async fn foo(mut a: Receiver<()>,mut b: Receiver<()>) {
let mut a_fut = a.recv();
let mut b_fut = b.recv();
loop {
tokio::select!{
_ = a_fut => {
println!("A!");
a_fut = a.recv();
}
_ = b_fut => {
println!("B!");
b_fut = b.recv();
}
}
}
}