Skip to content

并发基础

概念名称: 并发是多个任务交替执行,并行是多个任务同时执行。

最简示例

rust
use std::thread;

fn main() {
    let handle = thread::spawn(|| {
        println!("子线程运行");
    });
    handle.join().unwrap();
}
▶ Run

并发 vs 并行

┌─────────────────────────────────────────────────────┐
│          并发 vs 并行                                │
├─────────────────────────────────────────────────────┤
│                                                     │
│  并发 (Concurrency)                                 │
│  ┌───────────────────────────────────────────┐     │
│  │  多个任务交替执行                          │     │
│  │  ▓▓░░░░░░  任务 A                          │     │
│  │  ░░▓▓░░░░  任务 B                          │     │
│  │  ░░░░▓▓░░  任务 C                          │     │
│  └───────────────────────────────────────────┘     │
│  单个 CPU 核心,时间片轮转                           │
│                                                     │
│  并行 (Parallelism)                                 │
│  ┌───────────────────────────────────────────┐     │
│  │  多个任务同时执行                          │     │
│  │  ▓▓▓▓▓▓▓▓  任务 A (核心 1)                 │     │
│  │  ▓▓▓▓▓▓▓▓  任务 B (核心 2)                 │     │
│  │  ▓▓▓▓▓▓▓▓  任务 C (核心 3)                 │     │
│  └───────────────────────────────────────────┘     │
│  多个 CPU 核心,真正同时                             │
│                                                     │
└─────────────────────────────────────────────────────┘

为什么用它?

rust
// 没有并发:任务顺序执行,慢
for i in 0..3 {
    process_task(i);  // 每个任务等前一个完成
}

// 有并发:任务同时运行,快
let handles: Vec<_> = (0..3).map(|i| {
    thread::spawn(move || process_task(i))
}).collect();
for h in handles {
    h.join().unwrap();
}
▶ Run

Rust 并发优势

Rust 在编译时防止数据竞争!

数据竞争条件:
1. 两个或以上线程同时访问同一数据
2. 至少有一个线程在写入
3. 没有同步机制

Rust 的所有权系统 + 类型系统 = 编译时消除数据竞争

创建线程

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

fn main() {
    // 创建线程
    let handle = thread::spawn(|| {
        for i in 1..10 {
            println!("子线程:{}", i);
            thread::sleep(Duration::from_millis(10));
        }
    });

    // 主线程工作
    for i in 1..5 {
        println!("主线程:{}", i);
        thread::sleep(Duration::from_millis(10));
    }

    // 等待子线程完成
    handle.join().unwrap();

    println!("完成!");
}
▶ Run

关键代码说明:

代码含义为什么这样写
`thread::spawn({...})`
handle.join()等待线程完成阻塞直到线程结束
move 闭包转移所有权到线程线程需要拥有捕获的数据
thread::sleep()暂停线程模拟耗时操作
┌─────────────────────────────────────────────────────┐
│ 并发 vs 并行 │
├─────────────────────────────────────────────────────┤
│ │
│ 并发 (Concurrency) │
│ ┌───────────────────────────────────────────┐ │
│ │ 多个任务交替执行 │ │
│ │ ▓▓░░░░░░ 任务 A │ │
│ │ ░░▓▓░░░░ 任务 B │ │
│ │ ░░░░▓▓░░ 任务 C │ │
│ └───────────────────────────────────────────┘ │
│ 单个 CPU 核心,时间片轮转 │
│ │
│ 并行 (Parallelism) │
│ ┌───────────────────────────────────────────┐ │
│ │ 多个任务同时执行 │ │
│ │ ▓▓▓▓▓▓▓▓ 任务 A (核心 1) │ │
│ │ ▓▓▓▓▓▓▓▓ 任务 B (核心 2) │ │
│ │ ▓▓▓▓▓▓▓▓ 任务 C (核心 3) │ │
│ └───────────────────────────────────────────┘ │
│ 多个 CPU 核心,真正同时 │
│ │
└─────────────────────────────────────────────────────┘

### Rust 并发优势

Rust 在编译时防止数据竞争!

数据竞争条件:

  1. 两个或以上线程同时访问同一数据
  2. 至少有一个线程在写入
  3. 没有同步机制

Rust 的所有权系统 + 类型系统 = 编译时消除数据竞争







## 创建线程

### 基本用法

```rust
use std::thread;
use std::time::Duration;

fn main() {
    // 创建线程
    let handle = thread::spawn(|| {
        for i in 1..10 {
            println!("子线程:{}", i);
            thread::sleep(Duration::from_millis(10));
        }
    });

    // 主线程工作
    for i in 1..5 {
        println!("主线程:{}", i);
        thread::sleep(Duration::from_millis(10));
    }

    // 等待子线程完成
    handle.join().unwrap();

    println!("完成!");
}

join vs detach

rust
use std::thread;

fn main() {
    // join: 等待线程完成
    let handle = thread::spawn(|| {
        println!("工作中...");
    });
    handle.join().unwrap();  // 阻塞直到完成

    // Rust 没有直接的 detach
    // 但可以通过不 join 来"分离"
    let _ = thread::spawn(|| {
        // 不 join,线程在后台运行
    });
    // 注意:程序退出时,未 join 的线程会被终止
}
▶ Run

带返回值

rust
use std::thread;

fn main() {
    let handle = thread::spawn(|| {
        let result = 42;
        result  // 返回值
    });

    // join 返回线程的返回值
    let value = handle.join().unwrap();
    println!("线程返回值:{}", value);  // 42
}
▶ Run