简体   繁体   English

从 tokio mpsc 频道获取最新消息

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM