bigywater.tech
Rust · 90

Mutex 与 RwLock

「读多写少就用 RwLock」是常见建议,但真实数据支持吗?这篇先验证 RwLock 的并行读优势,再验证 try 系列函数、同线程重复加锁的死锁,最后用极短临界区的微基准,看看 RwLock 什么时候反而更慢。

210 → 50
Mutex 与 RwLock 读锁:4 个线程各持 50 ms 的总耗时(ms)
6.1×
极短临界区下,RwLock 比 Mutex 慢的倍数(917.4 对 149.6 ms)
WouldBlock
try_lock / try_read / try_write 在锁被占用时的返回

串行与并行

实测 · 本机执行输出
  编译:成功
  运行(退出码 0):
    Mutex:     4 个线程各持锁 50 ms,总耗时约 210 ms(串行)
    RwLock 读: 4 个线程各持读锁 50 ms,总耗时约 50 ms(并行)
    RwLock 写: 4 个线程各持写锁 50 ms,总耗时约 220 ms(写锁互斥,串行)

Mutex 的基础见Mutex<T> 与内部可变性。

读写锁的互斥关系

实测 · 本机执行输出
  编译:成功
  运行(退出码 0):
    持有写锁时:try_read = WouldBlock  try_write = WouldBlock
    持有读锁时:try_read = 成功  try_write = WouldBlock
    Mutex 持有时:try_lock = WouldBlock
    释放后:try_lock = 成功

重复加锁

实测 · 本机执行输出
  编译:成功
  运行(退出码 0):
    拿到第一把锁
    再等 300 ms:Err(Timeout)(同一线程第二次 lock 阻塞了)
    主线程 try_lock: 拿不到,锁被卡住的线程占着

极短临界区

实测 · 本机执行输出
  编译:成功
  运行(退出码 0):
    Mutex  4 线程 × 200 万次读:   149.6 ms
    RwLock 4 线程 × 200 万次读:   917.4 ms
    size_of::<Mutex<u64>>() = 24  size_of::<RwLock<u64>>() = 24  size_of::<u64>() = 8

这是 macOS aarch64 上的一次微基准,其它平台与读写比例下结论可能不同;没有测混合读写。毒化的行为见catch_unwind。

分步演示

Mutex 与 RwLock
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / rustc 1.98.1(brew)/ cargo 1.98.1;单个文件用 rustc 直接编译,需要依赖时用 cargo(经代理从 crates.io 下载);计时用 std::time::Instant,数字每次运行会有小幅抖动。耗时用 release 构建,各取 3 次最小
    • 没有验证:写者饥饿(读者源源不断时写者能否进入)、parking_lot 的 Mutex/RwLock、Linux 上的表现、读写混合比例下的盈亏平衡点、锁的公平性
    京ICP备2026067502号-1京公网安备11010502063487号