Day 2:執行緒技巧與開關

學習目標

  • 用執行緒做並行工作
  • 收集多個執行緒的結果
  • 理解執行緒的開銷與限制

今日重點

收集多個執行緒結果

use std::thread;

fn main() {
    let mut handles = vec![];

    for i in 0..5 {
        let handle = thread::spawn(move || {
            i * i   // 回傳值
        });
        handles.push(handle);
    }

    // 依序 join 並收集結果
    let results: Vec<i32> = handles
        .into_iter()
        .map(|h| h.join().unwrap())
        .collect();
    println!("{:?}", results);   // [0, 1, 4, 9, 16]
}

JoinHandle<T> 的 join 回傳 T,所以執行緒可以「回傳」結果。

執行緒限制與開銷

  • OS 執行緒建立有成本(記憶體、context switch)
  • 不要為極小工作就開執行緒
  • 大量並行任務 → 用執行緒池或 async(第 9 週)
  • 主執行緒結束,整支程式就結束(未 join 的子執行緒會被終止)

常用技巧

// 產生固定數量執行緒,各處理不同片段
let workers = 4;
let chunk = 100usize / workers;
// ... 分派工作

練習

use std::thread;
use std::time::Duration;

// 1. 開 3 個執行緒,各 sleep 不同時間回傳自己的編號
// 2. 收集並印出完成順序
fn main() {
    let mut handles = vec![];
    for i in 0..3 {
        handles.push(thread::spawn(move || {
            thread::sleep(Duration::from_millis(100 * i));
            i
        }));
    }
    for h in handles {
        println!("done: {}", h.join().unwrap());
    }
}

自我檢查

  • 會收集多執行緒的結果
  • 知道 join 回傳結果
  • 理解執行緒建立有開銷
  • 知道何時該考慮執行緒池 / async

深入連結

  • The Book 第 16 章「Using Threads to Run Code Simultaneously」