SuperAPI AI 工具集

m07-concurrency

编程与开发

查看项目

更新于 10-15 08:19

技能介绍

该技能的核心问题在于:当前任务是 CPU 密集型还是 I/O 密集型,以及采用什么样的共享模型。在选择并发原语之前,需要先回答三个问题:工作负载类型是什么、需要共享哪些数据、线程安全要求是什么。

它强调不要只修复编译错误,而应向上追溯设计约束。例如遇到 E0277 Send 错误时,不应草率地“加上 Send 约束”,而应先问该类型是否真的需要跨线程;遇到 Sync 错误时,不应直接“用 Mutex 包起来”,而要先确认是否真的需要共享访问;遇到 Future not Send 时,应考虑 async 是否是正确的选择;遇到死锁时,应审查锁设计是否正确。

在思考提示部分,工作负载决定方向:CPU 密集型使用 std::thread 或 rayon,I/O 密集型使用 tokio、async-std 等 async 方案,混合场景采用混合方式。共享模型决定手段:不共享则用消息传递(通道),不可变共享用 Arc,可变共享用 Arc<Mutex> 或 Arc<RwLock>。Send/Sync 要求则区分跨线程所有权(Send)、跨线程引用(Sync)以及单线程 async(spawn_local)。

它还提供了领域检测表,根据上下文关键词加载对应的领域技能:Web API/HTTP/axum/actix/handler 对应 domain-web,要求共享状态必须线程安全;交易/支付对应 domain-fintech,强调审计与线程安全;gRPC/kubernetes/微服务对应 domain-cloud-native,关注分布式追踪;CLI/终端/clap 对应 domain-cli,通常单线程即可。示例展示了在 Web API 场景下遇到“Rc cannot be sent between threads”时,应追溯为使用 Arc<T> 配合 State 提取器(如 axum::extract::State<Arc<AppConfig>>)。

在从设计到实现的下行路径中:CPU 工作并行用 std::thread 或 rayon;I/O 并发用 async/await 配合 tokio;跨线程共享不可变数据用 Arc<T>;共享可变数据用 Arc<Mutex<T>> 或 Arc<RwLock<T>>,也可用通道做消息传递;简单原子操作用 AtomicBool、AtomicUsize 等。

Send/Sync 标记说明:Send 表示所有权可在不同线程间转移(大多数类型),Sync 表示引用可在不同线程间共享(如 Arc<T>),!Send 表示必须留在单一线程(如 Rc<T>),!Sync 表示引用不能跨线程共享(如 RefCell<T>)。快速参考表列出各模式是否线程安全、是否阻塞及适用场景:std::thread 用于 CPU 密集型并行,async/await 用于 I/O 密集型并发,Mutex<T> 用于共享可变状态,RwLock<T> 用于读多写少的共享状态,mpsc::channel 用于消息传递,Arc<Mutex<T>> 用于跨线程共享可变数据。

决策流程为:先判断工作类型(CPU 密集型、I/O 密集型或混合),再判断是否需要共享数据(不需要用消息传递,不可变用 Arc<T>,可变时读多用 Arc<RwLock<T>>、写多用 Arc<Mutex<T>>、简单计数用 AtomicUsize),最后判断异步上下文(类型为 Send 用 tokio::spawn,类型为 !Send 用 spawn_local,阻塞代码用 spawn_blocking)。

常见错误与修复包括:E0277 Send not satisfied 由 async 中出现非 Send 类型导致,可用 Arc 或 spawn_local 解决;Sync 不满足由非 Sync 共享导致,可用 Mutex 包装;死锁由锁顺序导致,应保持一致的加锁顺序;future is not Send 由跨 await 持有非 Send 值导致,应在 await 前丢弃;MutexGuard across await 由挂起期间持有守卫导致,应正确限定作用域。反模式部分指出:到处使用 Arc<Mutex> 会带来争用与复杂度,消息传递更合适;async 中使用 thread::sleep 会阻塞执行器,应改用 tokio::time::sleep;跨 await 持有锁会阻塞其他任务,应尽量缩小锁作用域;忽视死锁风险难以调试,应采用锁顺序与 try_lock。

在 Async 特定模式中,给出了跨 await 持有 MutexGuard 的反例与正例,提倡用作用域限制锁并在 await 前释放;对于非 Send 类型,可改用 Arc、使用 spawn_local(单线程运行时)或确保在 .await 前丢弃。相关技能包括:智能指针选择参考 m02-resource,内部可变性参考 m03-mutability,性能调优参考 m10-performance,域并发需求参考 domain-*。