我可以通过在两个异步接收器上调用select来错过一个值吗?

问题描述

是否有可能,如果一个任务发送到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();
            }
        }
    }
}