返回文章列表

文章

tokio::sync::Mutex和std::sync::Mutex的差别

tokio::sync::Mutex 和 std::sync::Mutex 都是 Rust 中用于实现互斥访问共享数据的工具

目录
  1. tokio::sync::Mutex 和 std::sync::Mutex 都是Rust中用于实现互斥访问共享数据的工具,但它们面向的场景完全不同。
  2. 🧩 核心区别总结
  3. ✅ 使用场景对比
  4. 📌 何时使用 std::sync::Mutex<T>
  5. 📌 何时使用 tokio::sync::Mutex<T>
  6. ⚠️ 注意事项
  7. 📌 选型建议总结
  8. 📎 参考文章

tokio::sync::Mutexstd::sync::Mutex 都是Rust中用于实现互斥访问共享数据的工具,但它们面向的场景完全不同。#

🧩 核心区别总结#

特性`std::sync::Mutex`(标准库)`tokio::sync::Mutex`(Tokio)
是否阻塞线程✅ 是,阻塞线程❌ 否,异步等待,不阻塞线程
是否支持 `.await`❌ 不支持✅ 支持 `.lock().await`
是否线程安全(Send + Sync)✅ 是✅ 是
[中毒机制(panic 安全)](/20b5c571bb7d806db760f3e7021a4ec5?pvs=25)✅ 有中毒检测❌ 没有中毒检测
性能快,轻量,适合 CPU 密集型任务较慢,适合异步 I/O 密集型任务
是否公平唤醒❌ 非公平唤醒✅ FIFO 公平唤醒
使用线程池(运行时)❌ 无需✅ 依赖 Tokio 运行时

✅ 使用场景对比#

📌 何时使用 std::sync::Mutex<T>#

🚫 不适用于异步代码中的 .await 位置! 适用场景:

  • 纯同步代码:没有异步逻辑的 Rust 应用,比如 CLI 工具、嵌入式系统等;
  • std::thread::spawn 中使用共享数据
  • 临界区非常短,只是简单修改少量数据;
  • 你需要 panic 中毒保护机制(某线程 panic 后,锁会中毒,可检测); 示例:
use std::sync::{Arc, Mutex};
use std::thread;

let counter = Arc::new(Mutex::new(0));
let mut handles = vec![];

for _ in 0..10 {
    let c = Arc::clone(&counter);
    let handle = thread::spawn(move || {
        let mut num = c.lock().unwrap();
        *num += 1;
    });
    handles.push(handle);
}

for handle in handles {
    handle.join().unwrap();
}

println!("Result: {}", *counter.lock().unwrap());

📌 何时使用 tokio::sync::Mutex<T>#

✅ 适合在 Tokio 异步任务中使用 适用场景:

  • 你在使用 Tokio 运行时,写异步应用
  • 你需要在持锁期间使用 ****.await(比如锁内访问数据库、发请求);
  • 你不关心中毒机制,只需要保证不会阻塞线程
  • 需要公平唤醒,减少饿死的风险; 示例:
use tokio::sync::Mutex;
use std::sync::Arc;

#[tokio::main]
async fn main() {
    let counter = Arc::new(Mutex::new(0));
    let mut handles = vec![];

    for _ in 0..10 {
        let c = Arc::clone(&counter);
        handles.push(tokio::spawn(async move {
            let mut num = c.lock().await;
            *num += 1;
        }));
    }

    for handle in handles {
        handle.await.unwrap();
    }

    println!("Result: {}", *counter.lock().await);
}

⚠️ 注意事项#

  • 千万不要在 async 中使用 std::sync::Mutex 并在持锁期间调用 ****.await

let lock = std::sync::Mutex::new(vec![]); let data = lock.lock().unwrap(); do_something_async().await; // ❌ 这会阻塞整个 Tokio 线程,可能导致死锁 ``` 应改用 tokio::sync::Mutex

  • Tokio 的 Mutex 开销更大,不要用在只需简单同步的同步场景下。

📌 选型建议总结#

代码类型是否需要 `.await`建议使用
同步函数`std::sync::Mutex`
异步函数否(无 .await)`std::sync::Mutex`(可以)
异步函数是(有 .await)✅ `tokio::sync::Mutex`

如你有具体的使用场景(比如 Tokio 的网络服务、异步数据库访问、多线程缓存等),可以告诉我,我可以帮你具体分析是否适合用哪一个。

📎 参考文章#