我可以通过在两个异步接收器上调用 select 来错过一个值吗?
Can I miss a value by calling select on two async receivers?
如果一个任务发送到 a
而另一个(同时)发送到 b
,那么 tokio::select!
在 a
和 b
通过取消剩余的未来来降低其中一个价值?还是保证在下一次循环迭代时收到?
use tokio::sync::mpsc::Receiver;
async fn foo(mut a: Receiver<()>, mut b: Receiver<()>) {
loop {
tokio::select!{
_ = a.recv() => {
println!("A!");
}
_ = b.recv() => {
println!("B!");
}
}
}
}
在那种情况下,我无法理解 async
魔法背后真正发生的事情。
它似乎并没有在任何地方的文档中得到保证,但由于 rusts 基于轮询的体系结构的工作方式,它可能适用于直接从频道读取。 select 相当于以随机顺序轮询每个期货,直到其中一个准备就绪,或者如果 none 准备就绪,则等待直到唤醒者发出信号,然后重复该过程。只有在 return 通过成功的轮询时,消息才会从频道中删除。成功的轮询会停止 select,因此不会触及其余频道。因此,下次循环发生时将轮询它们,然后 return 消息。
但是,这是一种危险的方法,因为如果接收器被替换为 return 未来比直接读取更复杂的东西,它可能会在读取后暂停,那么你发生这种情况时可能会丢失消息。因此,它可能应该被视为不起作用。一种更安全的方法是将 futures 存储在你在它们触发时更新的可变变量中:
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();
}
}
}
}
如果一个任务发送到 a
而另一个(同时)发送到 b
,那么 tokio::select!
在 a
和 b
通过取消剩余的未来来降低其中一个价值?还是保证在下一次循环迭代时收到?
use tokio::sync::mpsc::Receiver;
async fn foo(mut a: Receiver<()>, mut b: Receiver<()>) {
loop {
tokio::select!{
_ = a.recv() => {
println!("A!");
}
_ = b.recv() => {
println!("B!");
}
}
}
}
在那种情况下,我无法理解 async
魔法背后真正发生的事情。
它似乎并没有在任何地方的文档中得到保证,但由于 rusts 基于轮询的体系结构的工作方式,它可能适用于直接从频道读取。 select 相当于以随机顺序轮询每个期货,直到其中一个准备就绪,或者如果 none 准备就绪,则等待直到唤醒者发出信号,然后重复该过程。只有在 return 通过成功的轮询时,消息才会从频道中删除。成功的轮询会停止 select,因此不会触及其余频道。因此,下次循环发生时将轮询它们,然后 return 消息。
但是,这是一种危险的方法,因为如果接收器被替换为 return 未来比直接读取更复杂的东西,它可能会在读取后暂停,那么你发生这种情况时可能会丢失消息。因此,它可能应该被视为不起作用。一种更安全的方法是将 futures 存储在你在它们触发时更新的可变变量中:
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();
}
}
}
}