PAYATHON 2026

Rust 如何每两秒输出通道中的最新数据?

数据小许

结论

可以在子线程中缓存最近收到的数据,并用 recv_timeout 等待下一个两秒输出时刻。收到消息时更新缓存,等待超时后打印缓存内容。这样,定时器决定输出频率,通道消息则负责更新数据。

下面的接收循环可以替换原先使用 rx.iter() 的部分:

use std::sync::mpsc::{Receiver, RecvTimeoutError};
use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};

fn print_latest(rx: Receiver<Vec<String>>) {
    let interval = Duration::from_secs(2);
    let mut latest: Option<Vec<String>> = None;
    let mut next_print = Instant::now();

    loop {
        let wait = next_print.saturating_duration_since(Instant::now());

        match rx.recv_timeout(wait) {
            Ok(data) => {
                // 新数据只更新缓存;打印仍按固定的两秒节奏进行。
                latest = Some(data);
            }
            Err(RecvTimeoutError::Timeout) => {
                if let Some(data) = &latest {
                    let seconds = SystemTime::now()
                        .duration_since(UNIX_EPOCH)
                        .expect("SystemTime went backwards")
                        .as_secs()
                        % 60;
                    println!("[{}] - {:?}", seconds, data);
                }

                next_print += interval;
            }
            Err(RecvTimeoutError::Disconnected) => break,
        }
    }
}

启动接收线程时,将 rx 移入线程:

let receiver_thread = thread::spawn(move || print_latest(rx));

next_print 从当前时刻开始计时,因此收到第一组数据后,很快就会打印。之后每隔两秒打印一次。如果两次打印之间收到多组数据,缓存会保留最后收到的数据,并在下一个输出时刻打印。尚未收到数据时,示例不会打印空值。

通道关闭时的处理

所有 Sender 都被丢弃后,recv_timeout 会返回 Disconnected,循环随之结束。若希望最后一条消息在发送后继续重复打印一段时间,发送端需要在这段时间内保持通道连接。例如,发送完数据后等待所需时长,再释放最后一个 Sender,然后调用 receiver_thread.join()。

原代码末尾只等待了 2 毫秒,主线程很快便会结束,也没有等待接收线程完成。应根据希望重复输出的时长安排发送端的生命周期;若需要确保接收线程完成,再调用 join()。如果发送端关闭后仍要无限重复最后一条数据,就需要另行定义停止条件,不能在通道断开时直接退出。

备注:内容仅供参考。