文章
tokio::sync::Mutex和std::sync::Mutex的差别
tokio::sync::Mutex 和 std::sync::Mutex 都是 Rust 中用于实现互斥访问共享数据的工具
目录
tokio::sync::Mutex 和 std::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 的网络服务、异步数据库访问、多线程缓存等),可以告诉我,我可以帮你具体分析是否适合用哪一个。