并发编程基础:线程、进程、并发与并行

各位同学,咱们正式开始第二讲。在做国密SDK优化之前,有些基础概念得先掰扯清楚。别小看这些基础,很多并发瓶颈追根溯源,就是对这几个概念理解不透。

1. 进程与线程:到底有啥区别?

我记得刚入行那会儿,有同事问我“进程和线程啥区别”,我背了一堆定义,结果人家越听越糊涂。后来我用一个例子讲明白了:进程就像一家饭店,线程就是饭店里的服务员。饭店有自己的厨房、库房、大堂(内存空间),服务员共享这些资源,但每个服务员有自己的活儿要干。

核心差异一览表

特性进程线程
资源拥有独立地址空间、文件句柄等共享所在进程的资源
创建开销大(fork需要复制页表等)小(仅分配栈和寄存器)
通信方式需IPC(管道、共享内存、Socket)直接读写共享变量
隔离性高,一个进程挂了一般不影响别的低,一个线程写越界可能整个进程崩
切换代价高,需切换页表、刷新TLB低,仅切换寄存器和栈指针

我在项目中遇到过一个问题:有个国密签名服务,用多进程做负载隔离。结果业务高峰期时,进程创建太频繁,CPU全耗在fork和上下文切换上了。后来改成线程池,延迟降了一半。你想想看,进程切换确实太“重”了。

我个人的经验:在国密SDK这种高性能场景下,尽量用线程而不是进程。除非你需要强隔离(比如多租户场景),否则线程的开销优势很明显。

2. 并发与并行:别傻傻分不清

这两个词很多人混着用,其实完全是两码事。打个比方:你一边吃面一边刷手机——这叫并发(看起来同时做,其实是快速切换)。你左手写代码右手敲键盘——这叫并行(真的同时做)。

  • 并发(Concurrency):多个任务在同一个CPU核上交替执行,通过时间片轮转实现"同时"推进。
  • 并行(Parallelism):多个任务在不同CPU核上真正同时执行。

为什么必须分清?因为国密SDK的优化方向截然不同。如果瓶颈在单核并发,你要优化锁竞争、减少上下文切换;如果瓶颈在多核并行,你要考虑数据分片、NUMA亲和性。

我曾经踩过的坑:早期优化SM4加解密时,我盲目开了大量线程以为就能跑满多核。结果锁争用导致大量线程在等锁,CPU利用率上不去。后来才发现,并发不等于并行——你的任务如果串行依赖太多,再多核也是白搭。

这里给个直观对比表,你品品:

场景实现方式CPU核心数吞吐量观察
单核并发时间片轮转1总吞吐 ≤ 1核极限
多核并行任务分区到各核≥2理想倍速 = 核数
超线程并发一个核偷空跑两线程1(物理)提升约20%~30%

3. Amdahl定律:你的优化天花板在哪?

说白了,这个定律告诉你:即使你把并行的部分优化到飞起,整个系统的加速比也有上限——被串行部分卡死了。

公式很简单:

加速比 = 1 / ((1 - P) + P / N)

P = 可并行比例
N = CPU核心数

举个例子:假设你的国密验签任务,90%可以并行,剩下10%必须串行(比如最后的验签结果校验)。

  • 4核:加速比 = 1 / (0.1 + 0.9/4) ≈ 3.08
  • 16核:加速比 = 1 / (0.1 + 0.9/16) ≈ 6.40
  • ∞核:加速比 = 1 / 0.1 = 10(天花板!)

看到了吧?哪怕你有再多的核,串行那10%决定了最大只能加速10倍。这就是天花板。

实际案例:我在优化一个国密证书链验证SDK时,发现串行部分占到了30%(包括证书链校验、CRL检查等)。当时技术人员一窝蜂堆线程,结果加速比从没超过3.3。后来我们重构了串行流程,把能并行的部分拆出来(比如各证书签名验证并行),串行比例降到8%,加速比直接翻倍。

避坑指南:做并发优化前,先用性能分析工具(比如perf、vtune)量一下你的串行比例。如果串行超过20%,先优化串行逻辑,再堆核心。否则你就是在给跑车装火箭发动机,但前轮还是自行车轮胎。

下面是这一章的知识体系框架,我手绘了一张图,你看一眼就能串起来:

并发编程基础知识结构图 并发编程基础知识框架 进程 独立内存空间 切换开销大 线程 共享进程资源 切换开销小 并发 单核时间片轮转 逻辑同时 并行 多核同时执行 物理同时 Amdahl定律 串行比例决定上限 加速比公式 核心关系 线程是进程的执行单元 并行是并发的物理实现 Amdahl决定并行收益

这张图把四个概念串起来了。进程和线程是资源/执行的关系,并发和并行是逻辑/物理的关系,Amdahl定律则是评估并行收益的标尺。做国密SDK优化时,你脑子里得时刻挂着这张图——你现在在调哪一块?是减少线程切换(进程vs线程),还是提高并行度(并发vs并行),还是测串行比例(Amdahl)?

小结一下:今天我讲了三个基础但极其重要的概念。我个人习惯在开始任何并发优化前,先画一张类似上面的图,把当前系统的“进程/线程模型”、“并发/并行策略”、“串行比例”标出来。光这一张图,就能帮你避免一半的踩坑。

最后提醒:别觉得基础简单就跳过。我见过太多人,一上来就调线程数、改锁策略,结果问题出在进程设计不合理或者串行比例没算过。万丈高楼平地起,基础打牢了,后面咱们聊国密SDK的具体瓶颈时,你才跟得上。