并发模型大全

一份从 理论到实践 的并发知识体系 —— 涵盖 20+ 种并发模型,按进程级 / 线程级 / I/O / 协程 / 事件驱动 / 消息传递 / 数据并行 七大维度分类, 包含原理讲解、代码示例、优劣分析和场景推荐。

📐 核心概念辨析

在深入并发模型之前,先区分几组容易混淆的概念。这是理解后续所有模型的地基。

并发 (Concurrency) vs 并行 (Parallelism)

并发:多个任务在同一时间段内交替执行,看起来像是同时进行,实际上 CPU 在多个任务之间快速切换。核心是逻辑上的同时

并行:多个任务在同一时刻真正同时执行,需要多核 CPU 或多台机器。核心是物理上的同时

💡 一句话总结:并发是结构(如何组织),并行是执行(如何运行)。并发是并行的前提,但不一定需要并行。

同步 (Sync) vs 异步 (Async)

同步:调用方发起请求后,必须等待被调用方完成并返回结果,期间调用方线程被阻塞。

异步:调用方发起请求后立即返回,不等待结果。被调用方完成后通过回调、事件、Promise 等方式通知调用方。

💡 同步/异步描述的是调用方式(消息通信机制),关注的是「结果怎么回来」。

阻塞 (Blocking) vs 非阻塞 (Non-blocking)

阻塞:调用后线程被挂起,直到操作完成才恢复。期间线程不能做任何其他事情。

非阻塞:调用后立即返回一个状态(如 EAGAIN / EWOULDBLOCK),线程可以继续执行其他任务,稍后再检查操作是否完成。

💡 阻塞/非阻塞描述的是线程状态,关注的是「调用后线程能不能干别的」。

四者的关系矩阵

同步 Sync异步 Async
阻塞 Blocking 经典阻塞 I/O(read/write 卡住) 少见组合,通常无意义
非阻塞 Non-blocking 非阻塞 I/O + 轮询 / I/O 多路复用 真正的异步 I/O(如 IOCP、io_uring)

🖥️ 一、进程级并发

操作系统级别的并发单元。每个进程拥有独立的内存空间、文件描述符和系统资源,天然隔离,最安全但最重。

多进程 Multi-Process

利用操作系统的 fork()spawn() 创建多个独立的进程,每个进程有独立的内存空间,通过 IPC(进程间通信)如管道、消息队列、共享内存、Socket 等进行数据交互。

✅ 优势

  • 内存隔离,一个进程崩溃不影响其他
  • 充分利用多核 CPU
  • 安全性高,无数据竞争

❌ 劣势

  • 创建和切换开销大(PCB 上下文切换)
  • IPC 通信复杂且成本高
  • 内存占用大,每个进程加载完整运行时

🎯 适用场景

CPU 密集型计算、需要高隔离性的服务(如 Chrome 多进程架构、Nginx Worker)、Python 中绕过 GIL
# Python multiprocessing 示例
from multiprocessing import Process

def worker(name):
    print(f"Worker {name} running")

p1 = Process(target=worker, args=("A",))
p2 = Process(target=worker, args=("B",))
p1.start(); p2.start()
p1.join();  p2.join()

进程池 Process Pool

预先创建固定数量的进程,任务到来时从池中取出空闲进程执行,完成后归还。避免频繁创建/销毁进程的开销。

✅ 优势

  • 控制并发数量,防止资源耗尽
  • 复用进程,减少创建销毁开销

❌ 劣势

  • 池大小固定,峰值时可能排队
  • 无法弹性伸缩

🎯 适用场景

Web 服务器的 Worker 模型(Apache prefork)、批量数据处理、Python concurrent.futures.ProcessPoolExecutor

🧵 二、线程级并发

进程内的轻量执行单元。多个线程共享进程的内存空间,通信成本低,但也带来了数据竞争和同步问题。

多线程 Multi-Threading

在同一个进程内创建多个线程,共享堆内存,各自拥有独立的栈和寄存器。操作系统负责线程调度(抢占式),时间片轮转。需要锁机制来保护共享数据。

✅ 优势

  • 共享内存,通信成本几乎为零
  • 创建/切换比进程轻量得多
  • 充分利用多核

❌ 劣势

  • 数据竞争(Race Condition)
  • 死锁风险
  • 调试困难(Heisenbug)
  • Python 有 GIL、JS 单线程等语言限制

🎯 适用场景

I/O 密集型任务、GUI 程序(主线程负责 UI,Worker 线程负责计算)、Java/C++ 后端服务

线程池 Thread Pool

预先创建 N 个线程放入池中,通过任务队列分配工作。核心思路:用少量线程处理大量任务,避免线程创建/销毁开销。

任务1 任务2 任务3 任务队列 线程1 线程2 线程N

✅ 优势

  • 控制资源上限,防止线程爆炸
  • 线程复用,降低创建开销

❌ 劣势

  • 核心线程数需要经验调优
  • 任务阻塞会占用线程

🎯 适用场景

几乎所有生产级后端服务(Tomcat、Netty Worker Group、Java ThreadPoolExecutor、Python ThreadPoolExecutor

共享内存 + 锁 Shared Memory & Locking

多线程/多进程通过共享内存区域交换数据,必须配合同步原语保证正确性。这不是一个独立的「模型」,而是几乎所有多线程/多进程方案都要面对的核心问题

🔒 常用同步原语

原语作用典型场景
互斥锁 (Mutex)独占访问临界区保护共享变量
读写锁 (R/W Lock)读共享、写独占读多写少(缓存)
自旋锁 (Spinlock)忙等待,不放弃 CPU临界区极短的场景
信号量 (Semaphore)控制同时访问资源的数量连接池、限流
条件变量 (Condition)等待某个条件成立生产者-消费者
原子操作 (Atomic)无锁的 CAS 操作计数器、状态标志
Barrier所有线程到达后一起放行分阶段并行计算
💡 锁的核心矛盾:锁太少 → 数据竞争;锁太多 → 死锁 / 性能退化。现代趋势是尽量用 无锁数据结构 (Lock-Free)消息传递 替代共享内存加锁。

📡 三、I/O 模型

I/O 往往是现代应用的主要瓶颈。理解 I/O 模型是选择并发方案的关键。以下按照 Unix 网络编程的五种 I/O 模型展开。

同步阻塞 I/O Blocking I/O

应用调用 read(),如果内核数据未就绪,线程被挂起直到数据从内核拷贝到用户空间。这是最简单也最低效的模型。

应用调用recvfrom 线程阻塞等待 数据就绪+拷贝 返回结果

🎯 适用场景

简单脚本、不需要并发的单连接程序、或配合多线程/多进程使用

同步非阻塞 I/O Non-blocking I/O

将 socket 设为非阻塞模式,read() 立即返回。如果数据未就绪,返回错误码 EAGAIN,应用需要反复轮询直到数据就绪。CPU 空转严重,实际中很少单独使用。

调用recvfrom EAGAIN 再次调用 EAGAIN 再次调用 数据就绪!

I/O 多路复用 I/O Multiplexing

这是高性能网络服务的基石。一个线程同时监听多个 socket,当至少一个 socket 数据就绪时返回,然后逐个处理。核心思想:「一个线程管理多个连接」。

select / poll / epoll 阻塞等待任一就绪 返回就绪列表 逐个read处理

📊 select / poll / epoll 对比

selectpollepoll (Linux)kqueue (BSD/macOS)IOCP (Windows)
fd 上限1024(默认)无限制无限制无限制无限制
扫描方式全量遍历 O(n)全量遍历 O(n)事件驱动 O(1)事件驱动 O(1)完成端口
触发方式水平触发水平触发水平+边缘触发水平+边缘触发完成通知
内核数据每次传入全量 fd每次传入全量 fd事件表维护事件表维护端口绑定
💡 epoll 的两个关键优化:(1) 事件表维护在内核,不需要每次传入全部 fd;(2) 只返回就绪的 fd,不需要遍历全部。这就是 C10K 问题被解决的核心原因。

🎯 适用场景

Nginx、Redis(单线程 + epoll)、Netty、Node.js 底层 libuv、几乎所有高性能网络框架

异步 I/O Asynchronous I/O (AIO)

应用发起 aio_read()立即返回,内核在后台完成「等待数据 + 拷贝到用户空间」的全过程,完成后通过信号或回调通知应用。全程无阻塞。

aio_read 立即返回 内核后台处理 完成通知

🔧 主流异步 I/O 实现

  • IOCP (Windows):最成熟的异步 I/O 实现,Proactor 模式的典范
  • io_uring (Linux 5.1+):新一代异步 I/O,通过共享环形缓冲区实现零拷贝,性能远超 AIO
  • POSIX AIO:Linux 上基于线程池模拟,不是真正的内核异步,性能一般

🎯 适用场景

高性能文件 I/O(数据库存储引擎)、Windows 高性能网络服务、使用 io_uring 的现代 Linux 应用

🌀 四、协程 (Coroutine)

用户态的「轻量线程」,由程序自身调度而非操作系统。切换成本极低(纳秒级),可以在一个线程内实现数万并发。协程是解决 C10K/C100K 问题的用户态方案。

协程概述 Coroutine

协程是一种能在执行中主动让出(yield)控制权、之后再恢复(resume)的函数。与线程的抢占式调度不同,协程是协作式调度,切换点由程序员显式控制。

🏗️ 有栈协程 vs 无栈协程

有栈协程 (Stackful)无栈协程 (Stackless)
代表Go goroutine、Lua coroutine、Boost.Coroutine2Python asyncio、JS async/await、C++20 coroutine、Rust async
实现独立栈空间,可在任意嵌套函数中挂起编译器将 async 函数转换为状态机,只能在这一层挂起
内存每个协程 2~8KB 初始栈仅保存局部变量,通常几十字节
灵活度高,任意深度 yield受限于 async 函数边界

✅ 优势

  • 切换成本极低(寄存器操作,无需陷入内核)
  • 无锁(单线程内调度,无数据竞争)
  • 可以支撑百万级并发

❌ 劣势

  • 无法利用多核(需要配合多线程/多进程)
  • CPU 密集型任务会阻塞整个调度器
  • 调试和堆栈追踪困难

🎯 适用场景

高并发 I/O 密集型服务、API 网关、即时通讯、爬虫、微服务间调用

async / await Async / Await 模式

现代语言(Python、JS/TS、Rust、C#、Dart、Swift)普遍采用的协程语法糖。用同步风格的代码写异步逻辑,大幅降低心智负担。

📝 各语言 async/await 对比

# Python
async def fetch(url):
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as resp:
            return await resp.text()

// JavaScript
async function fetch(url) {
    const resp = await fetch(url);
    return await resp.text();
}

// Rust
async fn fetch(url: &str) -> Result<String> {
    let resp = reqwest::get(url).await?;
    resp.text().await
}
💡 函数染色问题:async 函数只能被 async 函数 await,导致 async 会「传染」整个调用链。Go(goroutine)和 Java(虚拟线程/Loom)不受此限制,这是它们的重要优势。

🔄 五、事件驱动模型

以事件循环为核心,将 I/O 事件、定时器、用户操作等抽象为事件,通过回调或状态机处理。是现代 Web 服务器和 GUI 框架的基础。

事件循环 Event Loop

事件循环是一个永远运行的循环,持续从事件队列中取出事件并分发给对应的处理器。典型流程:收集事件 → 分发事件 → 处理事件 → 循环

Event Queue 取出事件 调用Handler 执行完毕

🏗️ 经典实现

  • libevent / libev / libuv:跨平台事件循环库,Node.js 底层使用 libuv
  • Redis 事件循环:自实现的 aeEventLoop,单线程 + epoll
  • 浏览器事件循环:宏任务(setTimeout)+ 微任务(Promise)的两级队列

🎯 适用场景

Node.js 运行时、浏览器 JavaScript、Redis 单线程架构、GUI 框架(Qt、Electron)

Reactor 模式 Reactor Pattern

Reactor 模式 = 事件循环 + I/O 多路复用 + 事件分发。核心是同步非阻塞地监听事件,然后同步地(或分发到线程池)处理事件。

Reactor 的三种线程模型

  • 单 Reactor 单线程:Redis —— 简单高效,但一个 handler 阻塞会拖垮全局
  • 单 Reactor 多线程:Handler 交给线程池,Reactor 线程只负责 I/O
  • 主从 Reactor 多线程:Netty / Nginx —— MainReactor 负责 accept,SubReactor 负责读写和业务处理
💡 Reactor 的本质:I/O 就绪事件的通知是同步的(由 epoll_wait 返回),但事件处理可以异步分发。Reactor 告诉你「数据到了,你去读」,而 Proactor 告诉你「数据已经读好了」。

Proactor 模式 Proactor Pattern

Proactor 更进一步:I/O 操作完全由内核异步完成,完成后通知应用。应用不需要参与数据读取过程,只需处理已经准备好数据的结果。

典型实现是 Windows IOCP 和 Linux io_uring。内核帮你把数据读到缓冲区,然后通知你「数据已经在这了,直接处理」。

🎯 适用场景

Windows 高性能服务(IIS、SQL Server)、Linux io_uring 的现代应用、需要极低 CPU 开销的 I/O 密集型系统

📨 六、消息传递模型

不要通过共享内存来通信,而要通过通信来共享内存。这是 Go 语言的核心哲学,也是消息传递模型的基本理念。两大代表:CSP 和 Actor。

CSP Communicating Sequential Processes

CSP 由 Tony Hoare 于 1978 年提出。核心概念:协程(goroutine)+ 通道(channel)。数据通过 channel 在 goroutine 间传递,channel 本身是同步点,天然保证数据安全。

// Go — CSP 的典范实现
func main() {
    ch := make(chan string)

    go func() {          // goroutine(协程)
        time.Sleep(1 * time.Second)
        ch <- "hello"        // 通过 channel 发送
    }()

    msg := <-ch               // 通过 channel 接收(阻塞直到有数据)
    fmt.Println(msg)
}

// select 多路复用
select {
case msg1 := <-ch1:
    fmt.Println(msg1)
case msg2 := <-ch2:
    fmt.Println(msg2)
case <-time.After(1 * time.Second):
    fmt.Println("timeout")
}

📊 CSP vs Actor 关键区别

CSPActor
通信方式匿名 channel,收发双方不需要知道对方身份命名 Actor,直接向指定 Actor 的 mailbox 发消息
耦合度低(通过 channel 解耦)较高(需要知道目标 Actor 地址)
同步性无缓冲 channel = 同步;有缓冲 = 异步消息发送是异步的
代表Go、Clojure core.async、CrystalErlang/Elixir、Akka(Scala/Java)、Orleans(C#)

✅ 优势

  • 无锁设计,通过 channel 保证同步
  • 代码简洁,goroutine 极轻量(~2KB)
  • select 提供优雅的多路复用和超时控制

❌ 劣势

  • channel 使用不当会导致 goroutine 泄漏
  • 分布式场景下 channel 不适用(需借助 RPC/消息队列)

🎯 适用场景

Go 后端微服务、网络编程、需要高并发的任何场景(Go 生态)

Actor Model Actor 模型

Actor 模型由 Carl Hewitt 于 1973 年提出。每个 Actor 是一个独立计算单元,有自己的状态和 mailbox(消息队列)。Actor 之间完全通过异步消息通信,不共享任何内存。

Actor A→ 消息 → Actor B Mailbox Actor B 处理 可能创建新Actor / 发送新消息

🔑 三大核心原则

  1. 一切皆 Actor
  2. Actor 有自己的私有状态,外部无法直接访问
  3. 通信只能通过异步消息,没有共享内存

✅ 优势

  • 天然分布 —— Actor 可以分布在多台机器
  • 容错性强 —— Erlang OTP 的 Let It Crash 哲学,Supervisor 树自动恢复
  • 无锁、无共享、无数据竞争

❌ 劣势

  • 消息是异步的,执行顺序不确定
  • 数据拷贝开销(消息需序列化)
  • 调试和追踪困难

🎯 适用场景

高可用通信系统(WhatsApp 用 Erlang)、游戏服务器、IoT 消息处理、需要天然分布和容错的系统

🗂️ 七、数据并行模型

将大数据集切分为小块,分配给多个 worker 并行处理,最后汇总结果。适用于计算密集的批量数据处理场景。

MapReduce

Google 2004 年提出的大规模数据处理范式。分两个阶段:Map(将输入数据映射为键值对中间结果)→ Shuffle(按 key 分组)→ Reduce(对每组数据聚合)。

输入数据 Map (并行) Shuffle & Sort Reduce (并行) 输出结果

🎯 适用场景

Hadoop、大规模日志分析、倒排索引构建、分布式排序、ETL 数据处理

Fork / Join

将大任务递归地Fork(拆分)为小任务并行执行,最后Join(合并)结果。核心数据结构是工作窃取(Work-Stealing)双端队列,空闲线程从繁忙线程的队列尾部偷任务,实现负载均衡。

// Java ForkJoinPool — 递归求和
class SumTask extends RecursiveTask<Long> {
    protected Long compute() {
        if (high - low <= THRESHOLD) {
            return directSum(low, high);
        }
        mid = (low + high) / 2;
        left  = new SumTask(low, mid).fork();   // 异步拆分
        right = new SumTask(mid, high).fork();
        return left.join() + right.join();  // 等待并合并
    }
}
💡 工作窃取 (Work-Stealing):每个线程有自己的双端队列。线程从自己的队列头部取任务,从其他线程的队列尾部偷任务。这种设计极大减少了线程间的竞争。

🎯 适用场景

递归算法并行化(归并排序、快速排序)、并行流(Java Stream.parallel())、图像处理、科学计算

🔬 八、其他并发范式

一些独特或组合式的并发模式,在实践中同样非常重要。

单线程异步 Single-Threaded Async

Node.js 为典型代表:一个主线程 + 事件循环 + 异步非阻塞 I/O。主线程处理所有 JavaScript 代码,I/O 操作委托给 libuv 线程池或操作系统异步接口,完成后通过回调/事件返回主线程。

// Node.js — 单线程异步
const fs = require('fs');
const http = require('http');

// 非阻塞读取,完成后回调
fs.readFile('large.txt', (err, data) => {
    // 这个回调稍后在事件循环中执行
    console.log(data.length);
});
console.log('我先输出!');  // 这行先执行

✅ 优势

  • 无锁、无并发 bug
  • 编程模型简单(回调/Promise/async-await)
  • 内存开销低

❌ 劣势

  • CPU 密集任务会阻塞整个进程
  • 不能利用多核(需要 cluster/worker_threads)

🎯 适用场景

I/O 密集的 Web 服务、API 网关、实时应用(Socket.io)、轻量微服务

响应式编程 Reactive Programming

数据流(Stream)和变化传播为核心。将一切视为异步数据流,通过声明式操作符(map、filter、flatMap)组合和变换流。天然支持背压(Backpressure),即消费者可以通知生产者放慢速度。

代表:ReactiveX(RxJava、RxJS、RxSwift)、Project Reactor(Spring WebFlux 底层)、Akka Streams

🎯 适用场景

实时数据管道、UI 事件处理、股票行情推送、IoT 传感器数据流、微服务间的响应式通信

STM Software Transactional Memory

借鉴数据库事务思想,将对共享内存的读写包装为原子事务。事务内对共享变量的修改对其他线程不可见,提交时检测冲突,有冲突则回滚重试。代表:Clojure STM、Haskell STM、C++ 实验性实现。

✅ 优势

  • 无锁、无死锁(由 STM 引擎处理冲突)
  • 组合性好 —— 多个操作可以组合成一个大事务

❌ 劣势

  • 性能开销大(冲突重试)
  • 不适合 I/O 操作
  • 未成为主流,生态有限

🎯 适用场景

复杂的共享状态管理、需要事务语义的内存操作、Clojure 生态中的状态管理

流水线并发 Pipeline Concurrency

将处理流程拆分为多个阶段(Stage),每个阶段在独立的线程/进程中运行,阶段之间通过队列传递数据。类似于工厂流水线,多个物品可以在不同阶段同时处理。

数据源 阶段1:解析→ Queue → 阶段2:处理→ Queue → 阶段3:写入

🎯 适用场景

视频/音频编解码管道、ETL 数据处理、编译器前端(词法分析 → 语法分析 → 代码生成)、GPU 渲染管线

📊 全景对比表

将所有并发模型放在一张表中横向对比,快速了解各模型的核心特征。

模型 调度层级 通信方式 是否共享内存 并发单元开销 适合 I/O 密集 适合 CPU 密集 代表性实现
多进程 OS(内核态) IPC(管道/共享内存/Socket) ❌(隔离) 高(MB 级) ⭐⭐⭐ ⭐⭐⭐⭐⭐ Nginx Worker、Python multiprocessing
多线程 OS(内核态) 共享内存 + 锁 中(MB 级栈) ⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ Java Thread、pthread
线程池 OS(内核态) 共享内存 + 任务队列 ⭐⭐⭐⭐ ⭐⭐⭐⭐ ThreadPoolExecutor、ForkJoinPool
I/O 多路复用 OS(内核通知) 由上层决定 视上层 低(fd 注册) ⭐⭐⭐⭐⭐ epoll、kqueue、IOCP
异步 I/O (io_uring) 内核异步 共享环形缓冲区 极低 ⭐⭐⭐⭐⭐ ⭐⭐ Linux io_uring
协程 用户态协同 共享内存(单线程内) 极低(KB 级) ⭐⭐⭐⭐⭐ Python asyncio、Lua coroutine
goroutine (CSP) 用户态 + 抢占 Channel ❌(通过 channel) 极低(~2KB) ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐ Go
虚拟线程 JVM 用户态 共享内存 极低(堆外分配) ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐ Java 21 Virtual Threads (Loom)
事件循环 (单线程异步) 用户态事件循环 回调/Promise 极低 ⭐⭐⭐⭐⭐ Node.js、浏览器 JS
Actor 模型 用户态 异步消息 ⭐⭐⭐⭐ ⭐⭐⭐ Erlang/OTP、Akka
MapReduce 分布式框架 HDFS + Shuffle 高(集群) ⭐⭐ ⭐⭐⭐⭐⭐ Hadoop、Spark
Fork / Join OS 线程池 共享内存 + Work-Stealing ⭐⭐ ⭐⭐⭐⭐⭐ Java ForkJoinPool、Cilk
响应式编程 事件循环 异步流 视底层 ⭐⭐⭐⭐⭐ ⭐⭐ Reactor、RxJava
STM 用户态 事务内存 ⭐⭐ ⭐⭐⭐ Clojure ref、Haskell STM

🎯 选型决策指南

面对具体业务场景时,按以下决策树快速定位合适的并发模型。

决策树:我需要什么并发模型?

🔵 场景一:高并发 I/O 密集型服务(Web 服务、API 网关、代理)

首选:Go (goroutine + channel)Java 21 虚拟线程
备选:Node.js(单线程异步)、Rust async(极致性能)、Erlang/Elixir(高可用需求)。
不建议:传统多线程(C10K 问题)、Python asyncio(CPU 受限)。

🟢 场景二:CPU 密集型计算(科学计算、图像处理、ML 推理)

首选:多进程 或 Fork/Join 线程池
备选:GPU 并行(CUDA)、MapReduce(大规模分布式)。
不建议:单线程事件循环、协程(单线程阻塞问题)。

🟡 场景三:混合负载(既要高并发 I/O,又偶尔有 CPU 密集任务)

首选:Go —— goroutine 调度器会自动在 OS 线程间迁移,CPU 密集任务不会饿死 I/O。
备选:Node.js + Worker Threads、Python asyncio + ProcessPoolExecutor。
模式:异步主线程处理 I/O,CPU 任务隔离到专用线程/进程池。

🟠 场景四:需要强一致性的共享状态(金融交易、库存扣减)

首选:单线程事件循环(如 Redis 单线程模型) —— 天然串行化,无竞争。
备选:Actor 模型(通过消息串行化)、STM(事务语义)。
不建议:多线程 + 细粒度锁(死锁地狱)。

🔴 场景五:分布式 + 高可用系统

首选:Actor 模型(Erlang/Elixir) —— 天然支持分布式、容错和热更新。
备选:Go + 消息队列(Kafka/NATS)模拟消息传递。
核心:用消息传递替代 RPC 直接调用,实现松耦合和故障隔离。

⚪ 场景六:前端 / GUI 应用

首选:事件循环 + 响应式编程
UI 线程(事件循环)保持响应,耗时操作放入 Worker 线程,通过消息/事件通信。
代表:浏览器 JS、Flutter (Isolate)、Android (Handler/Looper)、iOS (GCD)。

💡 核心原则总结

  1. I/O 密集 → 用异步(协程 / 事件循环 / goroutine),不要让线程在 I/O 上白白等待
  2. CPU 密集 → 用多核(多进程 / Fork-Join / GPU),让每个核心都跑满
  3. 共享状态复杂 → 用消息传递(CSP / Actor),不要通过共享内存来通信
  4. 高可用需求 → 用 Actor(Let It Crash + Supervisor 树),容错是第一优先级
  5. 简单优先 → 单线程异步足够时不要上多线程,复杂度往往比性能损耗更昂贵
  6. 没有银弹 —— 现代系统通常是多种模型的组合(如 Rust:tokio 异步运行时 + rayon 数据并行 + channel 消息传递)