Rust 并发共享数据选型总结:Mutex vs ArcSwap

Rust 并发共享数据选型总结:Mutex vs ArcSwap

本文档清晰对比 Rust 开发中读多写少、共享可变数据场景下最常用的两种方案:Arc<Mutex<T>>Arc<ArcSwap<T>>,并补充常用拓展方案,用于快速选型、记忆和团队参考。

一、核心对比(速查版)

特性Arc<Mutex<Vec<T>>>Arc<ArcSwap<Vec<T>>>
核心原理互斥排他锁,同一时间只允许一个线程访问无锁原子指针替换,读写分离
并发读阻塞,多线程读必须排队无锁,海量线程同时读无性能损耗
并发写阻塞所有读写操作不阻塞读,仅原子替换指针
数据修改原地修改写时复制(COW),生成新数据替换
性能表现低并发可用,高并发锁竞争严重读性能极高,高并发首选
一致性强一致性,修改立即生效最终一致性,读拿到当前快照
使用难度简单,lock 即可读写稍复杂,写需要克隆 + 替换
适用场景读写频繁、需要强一致性读多写少(规则 / 配置 / 白名单)

二、详细定义与用法

1. Arc<Mutex<T>>

  • 依赖:Rust 标准库,无需额外引入

  • 作用:多线程安全共享可变数据,通过互斥锁保证同一时间只有一个线程操作数据

  • 结构含义:

    • Arc:原子引用计数,支持跨线程共享所有权

    • Mutex:互斥锁,提供独占访问能力

基础用法

use std::sync::{Arc, Mutex};

// 初始化
let shared_data = Arc::new(Mutex::new(vec![1, 2, 3]));

// 读/写:必须加锁,阻塞等待
let mut data = shared_data.lock().unwrap();
data.push(4); // 原地修改

2. Arc<ArcSwap<T>>

  • 依赖:第三方库 arc-swap

  • 作用:高并发读、极少写场景的最优解,无锁读、原子写

  • 结构含义:

    • ArcSwap:无锁数据结构,原子替换 Arc 指针

    • 读操作无锁,写操作不影响正在进行的读

基础用法

use arc_swap::{ArcSwap, Arc};
use std::sync::Arc as StdArc;

// 初始化
let shared_data = ArcSwap::from(StdArc::new(vec![1, 2, 3]));

// 读:无锁,瞬间完成
let current = shared_data.load();

// 写:创建新数据,原子替换
let new_data = StdArc::new(vec![1, 2, 3, 4]);
shared_data.store(new_data);

三、记忆口诀(永久不忘)

  1. Mutex** = 公共厕所** 读写都要排队,一次只能一个人用,阻塞、独占、低并发

  2. ArcSwap** = 公告栏** 多人同时看(读无锁),管理员直接换新海报(写替换),不影响读者


四、业务选型指南

✅ 推荐使用 Arc<Mutex<T>>

  • 数据读写都很频繁

  • 需要强一致性,修改必须立即生效

  • 逻辑简单,不想处理写时复制

  • 并发量低,无性能压力

✅ 推荐使用 Arc<ArcSwap<T>>

  • 读多写少(99% 业务场景)

  • 配置、规则、路由表、白名单、静态数据

  • 高并发、低延迟要求

  • 允许最终一致性(读取快照)


五、常用拓展方案(补充)

除了上述两种,Rust 并发共享数据还有以下高频方案,可根据场景扩展使用:

1. Arc<RwLock<T>> 读写锁

  • 特点:读共享、写独占

  • 对比:

    • Mutex 并发读更强

    • ArcSwap 写更方便(原地修改)

  • 适用:读多写少,希望写操作简单、强一致性

  • 缺点:高并发读性能不如 ArcSwap

2. OnceCell / LazyCell

  • 特点:一次性初始化,只读不写

  • 适用:全局配置、单例、启动加载后永不修改的数据

  • 优点:无锁、零开销、最简单安全

3. tokio::sync::Mutex

  • 特点:异步互斥锁,用于 async 代码

  • 适用:异步任务中共享可变数据

  • 注意:不能在同步代码中使用,不要与标准库 Mutex 混用


六、最终总结

  1. 标准库、简单场景、读写均衡 → 用 Arc<Mutex<T>>

  2. 高并发读、规则 / 配置、读多写少 → 用 Arc<ArcSwap<T>>

  3. 读多写少、希望写方便 → 用 Arc<RwLock<T>>

  4. 初始化后永不修改 → 用 OnceCell/LazyCell

  5. 异步环境 → 用 tokio::sync::Mutex


本文由萧兮的博客原创发布,欢迎转载,转载务必保留原文链接。

萧兮的博客https://www.20010515.xyz · 原文:https://www.20010515.xyz/posts/019e8cc4-27b0-7670-b3b4-645bcfef0d32