[Rust] 併發程式設計全景指南
一、 全景知識心智圖
Rust Concurrency (併發程式設計全景)
├── 1. 核心底層 (Foundations)
│ ├── Trait 標記 : Send (所有權可跨執行緒轉移) / Sync (不可變參考可跨執行緒共享)
│ └── 生命週期 : 'static (thread::spawn 要求完整所有權 move 或 static 變數)
│
├── 2. 模式 A:純訊息傳遞 (Channel / CSP)
│ ├── 核心組件 : std::sync::mpsc (Multi-Producer, Single-Consumer)
│ ├── 生產者 (tx) : tx.clone() 多端發送 | drop(tx) 顯式關閉管道
│ └── 消費者 (rx) : rx.recv() 三態機制 (Ok 運算 | 佇列空 0% CPU 休眠 | drop(tx) 退出)
│
├── 3. 模式 B:純共享記憶體 (Shared Memory / Mutex)
│ ├── 核心組件 : Arc<Mutex<T>> (原子引用計數 + 互斥鎖)
│ └── 黃金七特徵 : Arc → Mutex → Arc::clone → thread::spawn → move → lock().unwrap() → RAII Drop
│
└── 4. 生態系高階替換 (Ecosystem vs C#)
├── Concurrent Collection : DashMap (分段鎖,對標 C# ConcurrentDictionary)
├── Parallel Computing : Rayon (.par_iter(),對標 C# PLINQ)
└── High-Perf Cache : Moka (帶 TTL/LRU Cache,對標 C# MemoryCache)
二、 模式 A:純訊息傳遞 (Channel)
適用場景:解耦生產者與消費者、任務佇列、流水線處理。資料所有權會直接從發送端移交給接收端。
use std::sync::mpsc;
use std::thread;
fn main() {
// 建立管道:產生發送端 (tx) 與接收端 (rx)
let (tx, rx) = mpsc::channel::<String>();
// 生產者 A
let tx1 = tx.clone();
thread::spawn(move || {
tx1.send("來自 Task A 的訊息".to_string()).unwrap();
});
// 生產者 B
thread::spawn(move || {
tx.send("來自 Task B 的訊息".to_string()).unwrap();
});
// 消費者:主執行緒直接迭代 rx (背後自動呼叫 rx.recv())
// 當所有 tx 離開作用域被 drop 後,迴圈會自動優雅終止
for msg in rx {
println!("收到: {}", msg);
}
}
rx.recv() 三態運作機制 |
系統行為 | CPU 占用 |
|---|---|---|
| 1. 有資料 (Ok) | 瞬間取出資料所有權,繼續執行下一步 | 正常運算占用 |
| 2. 沒資料且管道開啟 | 執行緒阻塞休眠 (Blocked),等待新資料 | 0% CPU |
| 3. 沒資料且所有 tx 已 drop (Err) | 回傳 Err,迴圈中斷退場 (Graceful Shutdown) | 執行緒結束銷毀 |
三、 模式 B:純共享記憶體 (Arc + Mutex)
適用場景:跨執行緒讀寫同一個狀態(如計數器、狀態機、全域設定)。完全展示了「黃金七特徵」。
use std::sync::{Arc, Mutex};
use std::thread;
fn main() {
// 1 & 2. 用 Arc> 包裹共享資料
let counter = Arc::new(Mutex::new(0));
let mut handles = vec![];
for _ in 0..10 {
// 3. Arc::clone:增加多執行緒引用計數
let counter = Arc::clone(&counter);
// 4 & 5. thread::spawn + move:把複製的指標移入新執行緒
let handle = thread::spawn(move || {
// 6. lock().unwrap():搶鎖並取得內部資料的可變參考
let mut num = counter.lock().unwrap();
*num += 1;
// 7. RAII Drop:num 離開作用域時,鎖自動釋放
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
println!("最終計數結果: {}", *counter.lock().unwrap());
}
黃金七特徵口訣:Arc → Mutex → Arc::clone → thread::spawn → move → lock().unwrap() → RAII Drop
四、 架構選型決策樹
[我有併發處理需求]
│
┌───────────────┴───────────────┐
需要共享狀態? 不需要共享狀態
(Shared Mutation) (Data Parallelism)
│ │
┌──────┴──────┐ ▼
狀態更新頻率? 資料解耦/管道 使用 Rayon
(State Type) (Message) .par_iter()
│ │ (對標 C# PLINQ)
│ ▼
│ 使用 Channel
│ mpsc::channel
│ │
│ ┌───────┴───────┐
│ 單消費者 多消費者 (Worker Pool)
│ │ │
│ ▼ ▼
│ 純 rx Arc<Mutex<rx>>
│
├────────────────────────┐
▼ ▼
一般全域狀態保護 高併發熱點 Key-Value Map
│ │
▼ ▼
Arc<Mutex<T>> DashMap
(標準庫黃金七特徵) (第三方套件/分段鎖)
留言
張貼留言