Day 6:Arc、Mutex 與並發設計
學習目標
- 深入 Arc / Mutex 的組合
- 比較「訊息傳遞 vs 共享狀態」
- 理解 Send / Sync trait
今日重點
訊息傳遞 vs 共享狀態
| 訊息傳遞 | 共享狀態(Mutex) | |
|---|---|---|
| 推薦度 | 較推薦(Go 口號:don't share, pass message) | 需要時用 |
| 心智負擔 | 低,資料靠通道傳 | 高,要小心鎖 |
| 死鎖風險 | 低 | 中 |
| 適合 | 工作分派、事件流 | 共享計數器、快取 |
Rust 兩者都有,掌握取捨是重點:優先訊息傳遞;需要緊密共享才 Mutex。
Send / Sync
- Send:型別可以安全地**轉移所有權**到另一執行緒
- Sync:型別可以安全地**被多執行緒同時引用**
Mutex<T>是 Sync;Rc<T>不是(Send/Sync 都是自動推導,除非含 unsafe)
Arc> 範例:共享取得訊息的 worker
use std::sync::{Arc, Mutex, mpsc};
use std::thread;
fn main() {
let (tx, rx) = mpsc::channel();
let rx = Arc::new(Mutex::new(rx)); // 多執行緒共享一個接收端
let mut handles = vec![];
for id in 0..4 {
let rx = Arc::clone(&rx);
handles.push(thread::spawn(move || {
loop {
let job = rx.lock().unwrap().recv();
match job {
Ok(msg) => println!("worker {}: {}", id, msg),
Err(_) => break, // 通道關閉
}
}
}));
}
for i in 0..8 { tx.send(format!("job {}", i)).unwrap(); }
drop(tx);
for h in handles { h.join().unwrap(); }
}
練習
- 跑上面的 worker 範例,觀察輸出與結束。
- 想想為什麼要用
Arc<Mutex<Receiver>>而不是直接 clone rx。 - 用 dotenv 小題練習:寫一個「無死鎖」的好習慣(lock 的生命週期縮越短越好)。
自我檢查
- 能用 Arc
> 共享資料 - 能比較訊息傳遞 vs 共享狀態
- 知道 Send / Sync 的基本意義
- 能設計簡單的多執行緒 worker
深入連結
- The Book 第 16 章「Extensible Concurrency with the Sync and Send Traits」