[Rust] 併發程式設計全景指南

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
(標準庫黃金七特徵)             (第三方套件/分段鎖)
Rust Concurrency Architecture Guide • Decoupled Edition

留言

這個網誌中的熱門文章

[C#] 無法載入檔案或組件 或其相依性的其中之一。 找到的組件資訊清單定義與組件參考不符。 (發生例外狀況於 HRESULT: 0x80131040)

[Rust] Trait 設計模式元素拆解與組合規則

[VibeCoding] AI Vibecoding 的地基(下):五層架構的實作 Prompt