rust-concurrency
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseConcurrency vs Async
并发 vs 异步
| Dimension | Concurrency (threads) | Async (async/await) |
|---|---|---|
| Memory | Each thread has separate stack | Single thread reused |
| Blocking | Blocks OS thread | Doesn't block, yields |
| Use case | CPU-intensive | I/O-intensive |
| Complexity | Simple and direct | Requires runtime |
Key Insight: Threads for parallelism, async for concurrency.
| 维度 | 并发(线程) | 异步(async/await) |
|---|---|---|
| 内存 | 每个线程拥有独立的栈 | 复用单个线程 |
| 阻塞行为 | 阻塞操作系统线程 | 不阻塞,主动让出 |
| 适用场景 | CPU密集型 | I/O密集型 |
| 复杂度 | 简单直接 | 需要运行时支持 |
核心要点:线程用于并行处理,异步用于并发处理。
Send/Sync Quick Reference
Send/Sync快速参考
Send - Can Transfer Ownership Between Threads
Send - 可在线程间转移所有权
Basic types → automatically Send
Contains references → automatically Send
Raw pointers → NOT Send
Rc → NOT Send (non-atomic ref counting)Rule: If all fields are Send, the type is Send.
基础类型 → 自动实现Send
包含引用的类型 → 自动实现Send
裸指针 → 未实现Send
Rc → 未实现Send(非原子引用计数)规则:如果一个类型的所有字段都实现了Send,那么该类型自动实现Send。
Sync - Can Share References Between Threads
Sync - 可在线程间共享引用
&T where T: Sync → automatically Sync
RefCell → NOT Sync (runtime checking not thread-safe)
MutexGuard → NOT Sync (intentionally)Rule: is Send if is Sync.
&TT&T(当T: Sync时)→ 自动实现Sync
RefCell → 未实现Sync(运行时检查不具备线程安全性)
MutexGuard → 未实现Sync(有意设计)规则:若T实现了Sync,则&T自动实现Send。
Solution Patterns
解决方案模式
Pattern 1: Shared Mutable State
模式1:共享可变状态
rust
use std::sync::{Arc, Mutex};
let counter = Arc::new(Mutex::new(0));
let mut handles = vec![];
for _ in 0..10 {
let counter = Arc::clone(&counter);
let handle = std::thread::spawn(move || {
let mut num = counter.lock().unwrap();
*num += 1;
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}When to use: Multiple threads need to mutate shared data.
Trade-offs: Lock contention can limit scalability.
rust
use std::sync::{Arc, Mutex};
let counter = Arc::new(Mutex::new(0));
let mut handles = vec![];
for _ in 0..10 {
let counter = Arc::clone(&counter);
let handle = std::thread::spawn(move || {
let mut num = counter.lock().unwrap();
*num += 1;
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}适用场景:多个线程需要修改共享数据时。
权衡点:锁竞争可能会限制可扩展性。
Pattern 2: Message Passing
模式2:消息传递
rust
use std::sync::mpsc;
let (tx, rx) = mpsc::channel();
thread::spawn(move || {
tx.send("hello").unwrap();
});
println!("{}", rx.recv().unwrap());When to use: Threads communicate without shared state.
Trade-offs: Copy/move overhead for messages.
rust
use std::sync::mpsc;
let (tx, rx) = mpsc::channel();
thread::spawn(move || {
tx.send("hello").unwrap();
});
println!("{}", rx.recv().unwrap());适用场景:线程间无需共享状态即可通信时。
权衡点:消息存在复制/移动开销。
Pattern 3: Async Runtime (Tokio)
模式3:异步运行时(Tokio)
rust
use tokio;
#[tokio::main]
async fn main() {
let handle = tokio::spawn(async {
// Async task
fetch_data().await
});
let result = handle.await.unwrap();
}When to use: I/O-bound operations (network, filesystem).
Trade-offs: Requires async runtime, function coloring.
rust
use tokio;
#[tokio::main]
async fn main() {
let handle = tokio::spawn(async {
// 异步任务
fetch_data().await
});
let result = handle.await.unwrap();
}适用场景:I/O密集型操作(网络、文件系统)。
权衡点:需要异步运行时,存在函数着色问题。
Workflow
工作流程
Step 1: Choose Concurrency Model
步骤1:选择并发模型
CPU-intensive task?
→ Use threads (rayon for data parallelism)
I/O-intensive task?
→ Use async/await (tokio, async-std)
Both?
→ Use async with spawn_blocking for CPU workCPU密集型任务?
→ 使用线程(数据并行可使用rayon)
I/O密集型任务?
→ 使用async/await(tokio、async-std)
两者兼具?
→ 使用异步,并通过spawn_blocking处理CPU密集型工作Step 2: Determine Data Sharing Strategy
步骤2:确定数据共享策略
No shared state?
→ Message passing (mpsc channels)
Read-heavy shared state?
→ Arc<RwLock<T>>
Write-heavy shared state?
→ Arc<Mutex<T>> or lock-free alternatives
Simple counters/flags?
→ Atomic types (AtomicUsize, AtomicBool)无共享状态?
→ 消息传递(mpsc通道)
读多写少的共享状态?
→ Arc<RwLock<T>>
写多读少的共享状态?
→ Arc<Mutex<T>>或无锁替代方案
简单计数器/标志位?
→ 原子类型(AtomicUsize、AtomicBool)Step 3: Verify Thread Safety
步骤3:验证线程安全性
Check Send bounds
→ Can transfer ownership?
Check Sync bounds
→ Can share references?
Test for data races
→ Use miri, loom, or thread sanitizers检查Send约束
→ 能否转移所有权?
检查Sync约束
→ 能否共享引用?
测试竞态条件
→ 使用miri、loom或线程sanitizerCommon Errors & Solutions
常见错误与解决方案
| Error | Cause | Solution |
|---|---|---|
| E0277 Send not satisfied | Contains non-Send types | Check all fields, replace Rc with Arc |
| E0277 Sync not satisfied | Shared reference type not Sync | Wrap with Mutex/RwLock |
| Deadlock | Inconsistent lock ordering | Establish and follow lock hierarchy |
| MutexGuard across await | Lock held while suspended | Scope lock before await point |
| Data race (runtime) | Improper synchronization | Use proper sync primitives |
| 错误 | 原因 | 解决方案 |
|---|---|---|
| E0277 Send约束不满足 | 包含非Send类型 | 检查所有字段,将Rc替换为Arc |
| E0277 Sync约束不满足 | 共享引用类型未实现Sync | 用Mutex/RwLock包裹 |
| 死锁 | 锁顺序不一致 | 建立并遵循锁层级 |
| await前后持有MutexGuard | 挂起时持有锁 | 在await点之前限定锁的作用域 |
| 运行时竞态条件 | 同步不当 | 使用正确的同步原语 |
Deadlock Prevention
死锁预防
Rule 1: Consistent Lock Ordering
规则1:保持一致的锁顺序
rust
// Always lock A before B
let _lock_a = resource_a.lock();
let _lock_b = resource_b.lock();
// Never lock B before A elsewhererust
// 始终先锁A再锁B
let _lock_a = resource_a.lock();
let _lock_b = resource_b.lock();
// 其他地方绝不能先锁B再锁ARule 2: Minimize Lock Scope
规则2:最小化锁的作用域
rust
// ❌ Bad: lock held too long
let guard = data.lock();
do_work(&guard);
more_work(); // still locked
// ✅ Good: release early
{
let guard = data.lock();
do_work(&guard);
} // lock released
more_work();rust
// ❌ 错误:持有锁时间过长
let guard = data.lock();
do_work(&guard);
more_work(); // 此时仍持有锁
// ✅ 正确:提前释放锁
{
let guard = data.lock();
do_work(&guard);
} // 锁已释放
more_work();Rule 3: Avoid Locks Across Await
规则3:避免在await前后持有锁
rust
// ❌ Bad: lock across await
let guard = mutex.lock().unwrap();
async_call().await; // DEADLOCK RISK
// ✅ Good: drop lock before await
let value = {
let guard = mutex.lock().unwrap();
guard.clone()
}; // lock dropped
async_call().await;rust
// ❌ 错误:await前后持有锁
let guard = mutex.lock().unwrap();
async_call().await; // 存在死锁风险
// ✅ 正确:在await之前释放锁
let value = {
let guard = mutex.lock().unwrap();
guard.clone()
}; // 锁已释放
async_call().await;Performance Considerations
性能考量
| Strategy | When to Use | Trade-offs |
|---|---|---|
| Fine-grained locking | Lock small portions | More complex, avoid contention |
| RwLock | Read-heavy workloads | Slower writes than Mutex |
| Atomics | Simple counters/flags | Limited operations, no compound ops |
| Message passing | Avoid shared state | Copy/move overhead |
| Lock-free structures | High contention | Complex, use crates (crossbeam) |
| 策略 | 适用场景 | 权衡点 |
|---|---|---|
| 细粒度锁 | 锁定小范围数据 | 实现更复杂,需避免竞争 |
| RwLock | 读密集型工作负载 | 写入速度比Mutex慢 |
| 原子类型 | 简单计数器/标志位 | 操作有限,不支持复合操作 |
| 消息传递 | 避免共享状态 | 存在复制/移动开销 |
| 无锁结构 | 高竞争场景 | 实现复杂,可使用crossbeam等crate |
Async-Specific Patterns
异步专属模式
Spawning Tasks
生成任务
rust
// Spawn independent task
tokio::spawn(async move {
process_data(data).await
});
// Spawn with 'static requirement
tokio::spawn(async move {
let data = Arc::clone(&data); // Share ownership
work_with(data).await
});rust
// 生成独立任务
tokio::spawn(async move {
process_data(data).await
});
// 生成满足'static约束的任务
tokio::spawn(async move {
let data = Arc::clone(&data); // 共享所有权
work_with(data).await
});Concurrent Operations
并发操作
rust
use tokio::join;
// Wait for all to complete
let (result1, result2, result3) = tokio::join!(
fetch_user(),
fetch_posts(),
fetch_comments()
);
// First to complete
let result = tokio::select! {
r = fetch_from_primary() => r,
r = fetch_from_backup() => r,
};rust
use tokio::join;
// 等待所有任务完成
let (result1, result2, result3) = tokio::join!(
fetch_user(),
fetch_posts(),
fetch_comments()
);
// 取第一个完成的任务结果
let result = tokio::select! {
r = fetch_from_primary() => r,
r = fetch_from_backup() => r,
};Timeout and Cancellation
超时与取消
rust
use tokio::time::{timeout, Duration};
match timeout(Duration::from_secs(5), long_operation()).await {
Ok(result) => result,
Err(_) => {
// Operation timed out
}
}rust
use tokio::time::{timeout, Duration};
match timeout(Duration::from_secs(5), long_operation()).await {
Ok(result) => result,
Err(_) => {
// 操作超时
}
}Review Checklist
审核检查清单
When reviewing concurrent code:
- All shared data properly synchronized (Arc/Mutex/RwLock)
- Send/Sync bounds satisfied for types crossing threads
- No locks held across await points
- Consistent lock ordering to prevent deadlocks
- Appropriate choice between threads and async
- Message passing channels used correctly (no deadlocks)
- Atomic operations used for simple shared state
- Thread pool sized appropriately for workload
- Error handling for lock poisoning
- Graceful shutdown and resource cleanup
审核并发代码时需检查:
- 所有共享数据都已正确同步(使用Arc/Mutex/RwLock)
- 跨线程的类型满足Send/Sync约束
- 未在await前后持有锁
- 保持一致的锁顺序以预防死锁
- 合理选择线程与异步模型
- 消息传递通道使用正确(无死锁)
- 简单共享状态使用原子操作
- 线程池大小与工作负载匹配
- 处理锁中毒错误
- 优雅关闭与资源清理
Verification Commands
验证命令
bash
undefinedbash
undefinedCheck compilation with thread safety
检查线程安全性相关编译问题
cargo check
cargo check
Run tests with thread sanitizer (requires nightly)
使用线程sanitizer运行测试(需要nightly版本)
RUSTFLAGS="-Z sanitizer=thread" cargo +nightly test
RUSTFLAGS="-Z sanitizer=thread" cargo +nightly test
Test with miri (detect undefined behavior)
使用miri测试(检测未定义行为)
cargo +nightly miri test
cargo +nightly miri test
Use loom for exhaustive concurrency testing
使用loom进行全面并发测试
cargo test --features loom
cargo test --features loom
Check for race conditions
检查竞态条件
cargo clippy -- -W clippy::mutex_atomic
undefinedcargo clippy -- -W clippy::mutex_atomic
undefinedCommon Pitfalls
常见陷阱
1. Rc in Multi-threaded Context
1. 多线程环境中使用Rc
Symptom: E0277 error, Rc<T> cannot be sent between threads
Fix: Replace with
RcArcrust
// ❌ Bad
let data = Rc::new(value);
thread::spawn(move || { /* use data */ });
// ✅ Good
let data = Arc::new(value);
thread::spawn(move || { /* use data */ });症状:出现E0277错误,Rc<T>无法在线程间传递
修复方案:将替换为
RcArcrust
// ❌ 错误
let data = Rc::new(value);
thread::spawn(move || { /* 使用data */ });
// ✅ 正确
let data = Arc::new(value);
thread::spawn(move || { /* 使用data */ });2. Lock Across Await Points
2. 在await前后持有锁
Symptom: Deadlock or "future cannot be sent between threads safely"
Fix: Drop lock before await
rust
// ❌ Bad
let guard = mutex.lock().unwrap();
async_fn().await;
// ✅ Good
let value = mutex.lock().unwrap().clone();
drop(guard); // Explicit drop
async_fn().await;症状:死锁或出现“future无法安全地在线程间传递”错误
修复方案:在await之前释放锁
rust
// ❌ 错误
let guard = mutex.lock().unwrap();
async_fn().await;
// ✅ 正确
let value = mutex.lock().unwrap().clone();
drop(guard); // 显式释放锁
async_fn().await;3. Missing Arc Clone
3. 未克隆Arc
Symptom: Borrow checker errors when spawning threads
Fix: Clone Arc before moving into closure
rust
// ❌ Bad
let data = Arc::new(vec![1, 2, 3]);
thread::spawn(move || { /* data moved */ });
// data is gone
// ✅ Good
let data = Arc::new(vec![1, 2, 3]);
let data_clone = Arc::clone(&data);
thread::spawn(move || { /* data_clone moved */ });
// data still available症状:生成线程时出现借用检查器错误
修复方案:在将Arc移动到闭包之前进行克隆
rust
// ❌ 错误
let data = Arc::new(vec![1, 2, 3]);
thread::spawn(move || { /* data被移动 */ });
// data已不可用
// ✅ 正确
let data = Arc::new(vec![1, 2, 3]);
let data_clone = Arc::clone(&data);
thread::spawn(move || { /* data_clone被移动 */ });
// data仍可使用Related Skills
相关技能
- rust-async - Advanced async patterns (Stream, select, backpressure)
- rust-async-pattern - Async architecture and design patterns
- rust-ownership - Understanding ownership for thread safety
- rust-mutability - Interior mutability patterns (Cell, RefCell)
- rust-performance - Concurrency performance optimization
- rust-unsafe - Writing safe concurrent abstractions
- rust-async - 高级异步模式(Stream、select、背压)
- rust-async-pattern - 异步架构与设计模式
- rust-ownership - 理解所有权以保障线程安全
- rust-mutability - 内部可变性模式(Cell、RefCell)
- rust-performance - 并发性能优化
- rust-unsafe - 编写安全的并发抽象
Localized Reference
本地化参考
- Chinese version: SKILL_ZH.md - 完整中文版本,包含所有内容
- 中文版本: SKILL_ZH.md - 完整中文版本,包含所有内容