[英]Take latest message from a tokio mpsc channel
I'm receiving messages from 2 channels every second and every 2 seconds, respectively.我每秒和每 2 秒分别从 2 个频道接收消息。 There is a function that needs to be run every time a message is received but this function takes 5 seconds.
每次收到消息时都需要运行一个函数,但这个函数需要 5 秒。 We're filling up the
result
channel way quicker than the time it takes for the expensive function to finish.我们填充
result
通道的速度比完成昂贵功能所需的时间要快。
The output of the below code looks something like this:以下代码的输出如下所示:
foo0
bar0
foo1
foo2
bar1
foo3
foo4
Data: {"processed-foo0": 0.7808990900831444}
bar2
foo5
foo6
bar3
foo7
foo8
bar4
foo9
Data: {"processed-foo0": 0.7808990900831444, "processed-bar0": 0.18431127449026619}
foo10
bar5
...
The expensive function is always run using the next message from the queue, not the latest and so it falls behind.昂贵的函数总是使用队列中的下一条消息运行,而不是最新的,因此它落后了。
How do I run the expensive function using the latest message from the result
channel?如何使用
result
通道中的最新消息运行昂贵的功能?
use std::{
collections::HashMap,
time::Duration,
sync::Arc,
};
use futures::future; // 0.3.21
use tokio::{
sync::{
mpsc::{self, UnboundedSender},
Mutex,
},
time,
}; // 1.16.1
use rand::Rng; // 0.8.5
use rand::rngs::StdRng;
use rand::SeedableRng;
pub struct Run;
impl Run {
async fn expensive_fn(data: Arc<Mutex<HashMap<String, f64>>>, message: &str) {
let mut rng: StdRng = SeedableRng::from_entropy();
let mut guard = data.lock().await;
guard.insert(message.to_string().clone(), rng.gen::<f64>());
time::sleep(Duration::from_millis(5_000)).await;
}
fn fast_fn(message: &str) -> String {
format!("processed-{message}")
}
}
async fn message_sender(msg: &str, tx: UnboundedSender<String>) {
for count in 0.. {
let message = format!("{msg}{count}");
if msg == "foo" {
time::sleep(Duration::from_millis(1_000)).await;
} else {
time::sleep(Duration::from_millis(2_000)).await;
}
tx.send(message).unwrap();
}
}
#[tokio::main]
async fn main() {
let (result_tx, mut result_rx) = mpsc::unbounded_channel();
let (foo_tx, mut foo_rx) = mpsc::unbounded_channel();
let (bar_tx, mut bar_rx) = mpsc::unbounded_channel();
let foo_sender_handle = tokio::spawn(message_sender("foo", foo_tx));
let bar_sender_handle = tokio::spawn(message_sender("bar", bar_tx));
let receive_handle = tokio::spawn(async move {
loop {
tokio::select! {
Some(foo_msg) = foo_rx.recv() => {
println!("{foo_msg}");
let result = Run::fast_fn(&foo_msg);
result_tx.send(result).unwrap();
},
Some(bar_msg) = bar_rx.recv() => {
println!("{bar_msg}");
let result = Run::fast_fn(&bar_msg);
result_tx.send(result).unwrap();
},
}
}
});
let expensive_fn_handle = tokio::spawn(async move {
let data = Arc::new(Mutex::new(HashMap::new()));
loop {
tokio::select! {
Some(result) = result_rx.recv() => {
Run::expensive_fn(data.clone(), &result).await;
}
}
println!("Data: {:?}", data.lock().await);
}
});
future::join_all([foo_sender_handle, bar_sender_handle, receive_handle, expensive_fn_handle]).await;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.