首页 › programming › 并发不是并行:把程序写成一条流水线

并发不是并行:把程序写成一条流水线

导语

2026年的硬件世界早就给所有开发者下过最后通牒:CPU 主频十几年前就停了,如今手机十来个核、服务器上百个核,你的代码跑不快,多半不是因为机器慢,而是因为你只写了一列“单线程的火车”。可讽刺的是,绝大多数工程师学并发的方式是背 API——synchronized、mutex、async/await 背得滚瓜烂熟,真要拆一个慢接口时依然两眼一抹黑,最后掏出的方案永远是“再开个线程,加把锁”。

如果你也有这个症状,那 Go 语言联合设计者 Rob Pike 的经典演讲 Concurrency Is Not Parallelism(并发不是并行)可能是最值得补的一课。这是他 2012 年初在 Heroku Waza 大会上的演讲,发布在 Go 官方 YouTube 频道,时长约半小时,累计播放量长期位居百万级以上,至今仍是几乎所有“并发编程入门”书单、课单的第一梯队常客。

这支演讲最狠的地方,是用一群卡通地鼠搬书,把一个困扰行业几十年的概念混淆一次性拆干净:并发(Concurrency)是关于程序结构的,并行(Parallelism)是关于程序执行的。结构问题用速度解决,注定南辕北辙。本文基于演讲内容逐段拆解,并补充从 2012 到 2026 年这十四年间,各个语言是如何接连验证 Pike 这个主张的。

视频背景卡片

项目 内容
视频标题 Concurrency Is Not Parallelism
演讲人 Rob Pike(Unix、UTF-8、Go 语言联合设计者,前贝尔实验室/Google)
频道 Go 官方频道
时长 约30分钟
播放量 长期百万级以上
发布背景 2012年初,Heroku Waza 开发者大会
核心主题 并发是结构设计问题,并行是执行效率问题;用任务分解与消息传递写出更好的程序

核心内容拆解

1. 开场先拆词:两个定义,一条分界线

Pike 开场做的第一件事不是写代码,而是抠定义。演讲中给出的两个定义大意是:并发,是把程序组织成一组相互独立执行的执行体(processes)的组合;并行,是让多个计算同时执行。一句话版本更有名:并发是“同时应对多件事”,并行是“同时做多件事”——前者关于管理,后者关于执行。

这两个词在日常语境里几乎被当成同义词用,但 Pike 明确指出:并发是关于结构的,并行是关于执行的。一个程序可以并发而不并行(单核跑 Go 程序,结构上是并发的,物理上轮流执行),也可以并行而不并发(一个任务被 SIMD 指令拆到多个核上,谈不上什么结构设计)。

延伸分析:这个区分在工程实践中的价值被严重低估。团队里“系统慢→加线程→死锁→加锁粒度→更慢”的死亡螺旋,源头几乎都是把结构问题误判成了性能问题。判断清楚你缺的是“更好的结构”还是“更多的核”,能省掉大半的无效优化。

2. 反直觉主张:并发的目的不是快,是易懂

这是全片最容易被误解、也最核心的论点。Pike 明确说(大意):并发的目的是让程序更容易写、更容易理解,它是一种程序结构设计工具;并行才是“让程序跑得更快”的工具。而最妙的一句推论是:如果你把并发结构设计对了,并行会自己涌现出来——你不需要为多核做任何特别的事,结构对了,把它扔到八核机器上它自然快。

这个主张在当时相当反直觉。2012年前后正是“多核焦虑”的顶峰,大家都在问“怎么利用多核”,Pike 的回答却是:别问怎么快,先问怎么把任务组织清楚。

延伸分析:这一思想和 Unix 管道一脉相承——cat log | grep error | wc -l 从不关心你有几个核,它只把“结构”写清楚,速度快慢交给操作系统调度。并发设计本质上是这套古老智慧的具象化。

3. 地鼠搬书:史上最便宜的任务分解教学

演讲中段的 Go gopher(地鼠)动画是这支视频流传最广的部分。情景很简单:一堆书要从A点搬到B点。方案零:一只地鼠来回搬,慢。直觉方案:多派几只地鼠各搬各的——这就是“并行思维”,人多力量大,但每一只地鼠依然在做完整的搬运流程,协作没变,只是堆数量。

Pike 给出的并发方案是重新设计结构:把搬运这个任务分解成角色——有的地鼠负责从书堆取书,有的负责运输,有的负责在目的地码放,中间用传送带衔接。每一只地鼠只做一件简单的事,整条“流水线”同时推进。更妙的是后续变化:给运输地鼠配推车(增加缓冲容量)、当某个环节成为瓶颈时就再细分或加一个并行单元。

整个动画想说的就一句话(大意):设计程序时,设计的是分工与协作关系,而不是执行过程。你描述“谁负责什么、通过什么交接”,而不是“第一步干什么第二步干什么”。

4. goroutine 与 channel:把 1978 年的论文变成工业语言

地鼠世界里“地鼠+传送带”,落到 Go 里就是 goroutine + channel。Pike 在演讲里交代了这套模型的理论源头:英国计算机科学家 Tony Hoare 1978 年的著名论文 Communicating Sequential Processes(CSP,通信顺序进程)——用独立顺序执行的进程、通过消息传递通信来构建系统。Go 是第一个把 CSP 思想内化为语言基本设施的工业级主流语言。

Go 的具体机制:go 关键字随手启动一个 goroutine,它极轻量(KB 级栈起步),由 Go 运行时把成千上万个 goroutine 多路复用到少量操作系统线程上,这个调度对程序员完全透明;channel 是带类型的通信管道,select 语句让你同时等待多个通道。Pike 在同年的另一场演讲 Go Concurrency Patterns 里把设计哲学浓缩成那句名言:不要通过共享内存来通信,而要通过通信来共享内存。

延伸分析:对比传统模型感受一下心智负担——线程+锁的世界里,你必须时刻在脑中维护“哪段数据被谁锁着”的幽灵地图;而 channel 模型里,数据的所有权随消息流动,同一时刻只有一个执行体持有它,一整类竞态问题从设计上就消失了。

5. 几十行的负载均衡器:结构对了,并行是赠品

演讲的后半段,Pike 用 Go 写了一个完整的并发负载均衡示例,总量不过几十行代码:一组 worker goroutine 从通道里领任务,干完活把结果送回;用通道实现任务的分发与均衡;甚至演示了带重试的闭环设计——失败的任务回流重做,忙的执行体自然少接活,均衡是结构自己“长”出来的行为,而不是一个精心调试的中央调度器。

关键结论回到那只地鼠:这套结构在单核机器上是一个“逻辑上并发”的、更好懂的程序;放到多核机器上,运行时自动把独立的 goroutine 分到不同核心,它就“物理上并行”了。同一个设计,两种硬件形态,代码一行不改。 这就是“结构对了,并行是赠品”的具体含义。

延伸分析:这几十行演示的“worker 池 + 任务通道”结构,到今天仍是后端系统的标准骨架——各种语言的队列消费者、爬虫调度、批量推送服务,骨架都是它。学这一段等于一次性看懂了半个云计算。

6. 延伸:为什么 2026 年回看,它反而更重要

这支演讲十四年过去,最大的变化是:当年 Pike 的一家之言,如今成了全行业的默认路径。Kotlin 把协程做进语言;Swift 用 async/await 和任务组实现了所谓“结构化并发”;Python 3.11 引入 TaskGroup,取消和错误传播有了统一的结构;Java 在 21 版正式带入虚拟线程,让“轻量执行体+阻塞式写法”成为 JDK 级能力;而云原生基础设施 Docker、Kubernetes 全部用 Go 写成——支撑起 2026 年互联网底座的代码,大量运行在 Pike 2012 年讲的那套模型上。

另一个时代注脚是 AI:大模型推理服务天然是流水线问题——请求排队、预填充、解码、流式输出,每一环吞吐不同、需要缓冲衔接。这本质上是“传送带地鼠”的算力版。

延伸分析:所有这些新工具的共同点是——都在把“启动执行体+传递数据”从危险操作变成普通代码结构,让并发回归 Pike 说的本位:一种让程序更清晰的组织手段,而非危险的速度外挂。

7. 一点观点:这支演讲真正的门槛是“反人性”

必须说句实话:这支演讲的道理不难懂,难的是照着做。因为它反人性——面对慢系统,人的第一反应永远是“加线程、加缓存、加机器”这种执行层的补丁,而 Pike 要求你退一步做结构层的手术:把流程摊开,找出独立的阶段,想清楚谁和谁通过什么交接。前者一下午就能改完,后者可能要重画架构图。

但代价的差距是复利的:补丁式并发每一层都在积累新的锁与竞态,半年后没人敢动;结构式并发画出来的那张“地鼠分工图”,三年后新同事看一眼就能接着维护。这支视频真正的价值,是把“先问结构、再问速度”这个判断顺序,用半小时焊进你的直觉里。

知识结构图

flowchart TD
    A["并发与并行:两个词,两件事"] --> B["并发 Concurrency"]
    A --> C["并行 Parallelism"]
    B --> D["结构设计:如何组织程序"]
    C --> E["执行方式:如何同时运算"]
    D --> F["并发设计的目的:更好写、更好懂"]
    F --> G["方法一:任务分解——地鼠分工"]
    F --> H["方法二:通信衔接——channel 传送带"]
    G --> I["goroutine:轻量执行流"]
    H --> I
    I --> J["结构一:流水线 Pipeline"]
    I --> K["结构二:负载均衡 Worker 池"]
    J --> L["结构正确,多核并行自然涌现"]
    K --> L

实战启示

第一步,诊断时先分类。 下次遇到“系统慢”,先在纸上写下:这是执行资源不足(并行问题),还是阶段耦合、互相等待(并发结构问题)?判断标准很简单——如果把机器规格翻倍就能解决,是前者;如果翻倍后依然卡在某把锁、某个串行环节上,是后者。

第二步,画出你的“地鼠图”。 把慢接口的处理流程摊开成阶段:取参数、查库、调外部服务、写缓存、返回。找出哪些阶段彼此独立、哪两个阶段之间需要“交接”。每一个交接点,就是一条 channel / 队列 / 消息总线的候选位置;每一个独立阶段,就是一个 goroutine / 协程 / 任务组的候选角色。按语言落工具:Go 用 goroutine+channel;Java 用虚拟线程;Kotlin 用协程;Python 用 asyncio 的 TaskGroup。

第三步,给交接加缓冲、给闭环加重试。 地鼠推车的对应物是有界队列——它吸收阶段间的速度差,也是天然的背压(backpressure)机制;失败任务回流的闭环,让你不需要中心化的“调度大脑”,均衡和容错都是结构自带的。

第四步,把这条判断带进 code review。 看到“新开线程+共享 Map+锁”的写法,试着追问一句:能不能改成“两个阶段通过队列交接”?这一句追问,往往比十条“注意线程安全”的评论更能防止事故。

延伸学习路径

  1. Rob Pike《Go Concurrency Patterns》(Google I/O 2012) — 本篇演讲的姊妹篇,channel 与 select 的模式手册,“通过通信共享内存”的名言出处。
  2. Go 官方博客《Go Concurrency Patterns: Pipelines and cancellation》 — 把流水线结构讲成可落地的工程规范,含取消与资源回收。
  3. 《Effective Go》Concurrency 一章 — 官方文档级的并发惯用法,适合边写边查。
  4. Nathaniel J. Smith《Notes on structured concurrency》 — “结构化并发”的标志性长文,讨论 Go 的 go 语句缺失了什么,是 2012 思想在 2018 年后的重要迭代。
  5. Tony Hoare《Communicating Sequential Processes》(1978) — 一切的源头。看不完全文没关系,读前几页就能感受到这套模型在理论上的干净。

一句话总结

并发是关于程序结构的智慧,并行只是结构对了之后多核硬件送你的赠品——先把分工与交接画清楚,快,是自然结果。

参考来源

  1. Concurrency Is Not Parallelism — Rob Pike, Heroku Waza 2012 — 本文分析的核心视频(Go 官方频道)
  2. Go Concurrency Patterns — Google I/O 2012 — Pike 同年姊妹演讲,channel 模式手册
  3. Go Concurrency Patterns: Pipelines and cancellation — Go Blog — 流水线结构的官方工程规范
  4. Notes on structured concurrency — Nathaniel J. Smith — 结构化并发的标志性讨论
  5. Effective Go — Go 官方惯用法文档,并发章节

本文由「51学通信」技术团队出品。51学通信由通信行业18年老兵爱卫生(微信ID: gprshome201101)维护,聚焦5G/6G核心网、3GPP标准解读、通信前沿技术深度分析。 出版作品有《5G核心网原理与实践》《IMS原理与实践》等4本通信专业书籍。知识星球「51学通信」提供深度技术答疑和行业洞察。

[!tip] 51学通信知识星球 星主:爱卫生(微信:gprshome201101)——公众号「51学通信」创办者,19 年通信行业运维与讲师经验,著有《GPRS网络信令实例详解》《EPC原理与实践》《5G核心网原理与实践》三本纸质书(各大电商平台有售)。 星球定位:深耕 5G 核心网、IMS、NFV/AI、云原生等 ICT 领域,主打运维岗位与信令分析。 当前规模:5200 篇主题 / 990 个回答,198 元/年。 加入福利:加入星球后请加爱卫生微信,拉您进知识星球年度陪伴与答疑群——不限量回复您的各种问题,另有群内分享。 AI 加持:51学通信知识星球已作为 skill 接入 WorkBuddy,使用 deepseek-4-flash 在海量星球帖子中精准找贴、找视频、找 FAQ 和案例,做总结、找文档和 PPT 等场景全覆盖。

51学通信知识星球海报-扫码加入