Loading...
Loading...
Compare original and translation side by side
| 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 |
| 维度 | 并发(线程) | 异步(async/await) |
|---|---|---|
| 内存 | 每个线程拥有独立的栈 | 复用单个线程 |
| 阻塞行为 | 阻塞操作系统线程 | 不阻塞,主动让出 |
| 适用场景 | CPU密集型 | I/O密集型 |
| 复杂度 | 简单直接 | 需要运行时支持 |
Basic types → automatically Send
Contains references → automatically Send
Raw pointers → NOT Send
Rc → NOT Send (non-atomic ref counting)基础类型 → 自动实现Send
包含引用的类型 → 自动实现Send
裸指针 → 未实现Send
Rc → 未实现Send(非原子引用计数)&T where T: Sync → automatically Sync
RefCell → NOT Sync (runtime checking not thread-safe)
MutexGuard → NOT Sync (intentionally)&TT&T(当T: Sync时)→ 自动实现Sync
RefCell → 未实现Sync(运行时检查不具备线程安全性)
MutexGuard → 未实现Sync(有意设计)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();
}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();
}use std::sync::mpsc;
let (tx, rx) = mpsc::channel();
thread::spawn(move || {
tx.send("hello").unwrap();
});
println!("{}", rx.recv().unwrap());use std::sync::mpsc;
let (tx, rx) = mpsc::channel();
thread::spawn(move || {
tx.send("hello").unwrap();
});
println!("{}", rx.recv().unwrap());use tokio;
#[tokio::main]
async fn main() {
let handle = tokio::spawn(async {
// Async task
fetch_data().await
});
let result = handle.await.unwrap();
}use tokio;
#[tokio::main]
async fn main() {
let handle = tokio::spawn(async {
// 异步任务
fetch_data().await
});
let result = handle.await.unwrap();
}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密集型工作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)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或线程sanitizer| 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点之前限定锁的作用域 |
| 运行时竞态条件 | 同步不当 | 使用正确的同步原语 |
// Always lock A before B
let _lock_a = resource_a.lock();
let _lock_b = resource_b.lock();
// Never lock B before A elsewhere// 始终先锁A再锁B
let _lock_a = resource_a.lock();
let _lock_b = resource_b.lock();
// 其他地方绝不能先锁B再锁A// ❌ 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();// ❌ 错误:持有锁时间过长
let guard = data.lock();
do_work(&guard);
more_work(); // 此时仍持有锁
// ✅ 正确:提前释放锁
{
let guard = data.lock();
do_work(&guard);
} // 锁已释放
more_work();// ❌ 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;// ❌ 错误:await前后持有锁
let guard = mutex.lock().unwrap();
async_call().await; // 存在死锁风险
// ✅ 正确:在await之前释放锁
let value = {
let guard = mutex.lock().unwrap();
guard.clone()
}; // 锁已释放
async_call().await;| 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 |
// 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
});// 生成独立任务
tokio::spawn(async move {
process_data(data).await
});
// 生成满足'static约束的任务
tokio::spawn(async move {
let data = Arc::clone(&data); // 共享所有权
work_with(data).await
});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,
};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,
};use tokio::time::{timeout, Duration};
match timeout(Duration::from_secs(5), long_operation()).await {
Ok(result) => result,
Err(_) => {
// Operation timed out
}
}use tokio::time::{timeout, Duration};
match timeout(Duration::from_secs(5), long_operation()).await {
Ok(result) => result,
Err(_) => {
// 操作超时
}
}undefinedundefinedundefinedundefinedRcArc// ❌ Bad
let data = Rc::new(value);
thread::spawn(move || { /* use data */ });
// ✅ Good
let data = Arc::new(value);
thread::spawn(move || { /* use data */ });RcArc// ❌ 错误
let data = Rc::new(value);
thread::spawn(move || { /* 使用data */ });
// ✅ 正确
let data = Arc::new(value);
thread::spawn(move || { /* 使用data */ });// ❌ Bad
let guard = mutex.lock().unwrap();
async_fn().await;
// ✅ Good
let value = mutex.lock().unwrap().clone();
drop(guard); // Explicit drop
async_fn().await;// ❌ 错误
let guard = mutex.lock().unwrap();
async_fn().await;
// ✅ 正确
let value = mutex.lock().unwrap().clone();
drop(guard); // 显式释放锁
async_fn().await;// ❌ 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// ❌ 错误
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仍可使用