You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rust中tokio::sync::watch的borrow与borrow_and_update区别解惑

区分tokio::sync::watch中borrow()和borrow_and_update()的差异

两者核心差异在于是否更新订阅者的"已查看版本"标记:

  • borrow():仅获取当前最新值的不可变引用,不会修改订阅者的版本标记。之前未被标记为已查看的更新,后续调用changed().await仍会检测到。
  • borrow_and_update():获取当前最新值引用的同时,将订阅者的版本标记同步到最新。后续changed().await会阻塞,直到发送端产生新的更新。

示例1:使用borrow()的行为

#[tokio::main]
async fn main() {
    use tokio::sync::watch;
    use tokio::time::{Duration, sleep};

    let (tx, mut rx) = watch::channel(0);

    tokio::spawn(async move {
        // 仅借用值,不更新版本标记
        println!("初始值:{}", *rx.borrow());
        
        // 连续发送两次更新
        tx.send(1).unwrap();
        tx.send(2).unwrap();
        
        // changed()立即返回,因为存在未标记的更新
        if rx.changed().await.is_ok() {
            println!("第一次changed后的值:{}", *rx.borrow());
        }
        
        // 再次调用changed()仍会立即返回,还有一次未处理的更新
        if rx.changed().await.is_ok() {
            println!("第二次changed后的值:{}", *rx.borrow());
        }
    });

    sleep(Duration::from_millis(100)).await;
}

运行结果:

初始值:0
第一次changed后的值:2
第二次changed后的值:2

这里borrow()没更新标记,两次send的更新都会被changed()捕获(watch仅保留最新值,旧更新会被覆盖)。

示例2:使用borrow_and_update()的行为

#[tokio::main]
async fn main() {
    use tokio::sync::watch;
    use tokio::time::{Duration, sleep};

    let (tx, mut rx) = watch::channel(0);

    tokio::spawn(async move {
        // 借用值的同时更新版本标记到最新
        println!("初始值:{}", *rx.borrow_and_update());
        
        // 连续发送两次更新
        tx.send(1).unwrap();
        tx.send(2).unwrap();
        
        // changed()立即返回,此时标记同步到最新的2
        if rx.changed().await.is_ok() {
            println!("changed后的值:{}", *rx.borrow());
        }
        
        // 再次调用changed()会阻塞,等待新的更新
        println!("等待新的更新...");
        match rx.changed().await {
            Ok(_) => println!("收到新值:{}", *rx.borrow()),
            Err(_) => println!("发送端已关闭"),
        }
    });

    sleep(Duration::from_millis(1000)).await;
    tx.send(3).unwrap();
    sleep(Duration::from_millis(100)).await;
}

运行结果:

初始值:0
changed后的值:2
等待新的更新...
收到新值:3

这里borrow_and_update()将标记更新到0的版本,两次send后changed()同步到最新的2版本,再次调用changed()会阻塞,直到新值3被发送。

为什么你的原示例看不出区别?

你的代码中同时使用了rx和rx2两个独立的订阅者,rx2的borrow/borrow_and_update操作不会影响rx的版本标记,两个订阅者状态完全独立,操作互不干扰,因此替换方法后rx.changed()的行为没有变化。

内容的提问来源于stack exchange,提问作者Shivam Varshney

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 23:48:09