四个各 5 拍的活儿:一核 20 拍、二核 10 拍、四核 5 拍,到四核就到顶了——再多的核没有活可派。这就是【核数超过任务数】的天花板。
4.13 给了方法,这一节用方法量出数据:同一批活儿、不同的核数,看到顶在哪里。
一、实验设置
四个各 5 拍的活儿,核数取 1/2/4/8/16。 关键在【每个活儿不能被拆开】——它就是一个整体,必须由一个核从头跑到尾。 这正是很多真实程序的形状:一个请求、一次计算、一次编译,多数时候是单线程的。
二、结果:四核到顶
20/10/5/5/5——从四核开始,总耗时不再下降。 加速比 1/2/4/4/4。第四行之后全是平的。 原因一句话:只有四个活儿,第五个核没活可派。核数超过并行任务数,多出来的核只是在闲着。 这个天花板不是调度器的错,是任务的并行度决定的。想再快,只能把活儿拆得更细。
三、这条结论怎么用
判断该不该加机器:先看你的程序同时能跑几个线程。如果只有 4 个线程,加到 16 核也不会有提升。
判断该不该改代码:如果 CPU 有 16 核而程序只用了 4 核,瓶颈在【并行度】——该拆任务,不是该买机器。
判据很简单:top 里这个进程的 CPU 占用能超过 100% 吗?不能,说明它是单线程的,加核无效。
四、这条规律的另一面
并行的代价:拆任务要写更多代码、要处理同步、要接受【有时候反而更慢】。 所以【能并行】不等于【值得并行】——一个每周跑一次、跑五分钟的批处理,花两周改成并行,不划算。 判断标准是【频率 × 单次耗时】:跑得越勤、单次越久,越值得拆。 这条在工程上比任何性能技巧都实用——它省下的是无谓的复杂度。
五、动手 Demo:实验结果——加速比不是线性的
先看【四个不可拆的活儿】在不同核数下的总耗时与加速比,再看阿姆达尔定律的理论曲线——两者说的是同一个道理。
# ① 四个各 5 拍的活儿,核数 1/2/4/8/16
for ncpu in (1, 2, 4, 8, 16):
ps = [Proc("P%d" % i, 5) for i in range(1, 5)]
done, _sw, _tl, total = run(ps, quantum=1, ncpu=ncpu)
# ② 阿姆达尔:九成并行、一成串行时的理论加速比
for ncpu in (1, 2, 4, 8, 16, 32, 64):
par = 0.9
speed = 1.0 / ((1 - par) + par / ncpu)
实跑输出:
--------------------------------------------------------------------
实验结果——加速比不是线性的
--------------------------------------------------------------------
① 一半的活儿可以并行,一半必须串行
核数 跑完用 加速比
----------------------------
1 20 1.00 倍
2 10 2.00 倍
4 5 4.00 倍
8 5 4.00 倍
16 5 4.00 倍
**四个各 5 拍的活儿,无论几个核,最后都要 5 拍以上**——
**因为每个活儿本身不能拆开。**
**核数超过任务数之后,再加核一点用都没有。**
② 这条规律有个名字:阿姆达尔定律
核数 理论加速比 比上一行快多少
---------------------------------------
1 1.00 倍 ——
2 1.82 倍 1.82 倍
4 3.08 倍 1.69 倍
8 4.71 倍 1.53 倍
16 6.40 倍 1.36 倍
32 7.80 倍 1.22 倍
64 8.77 倍 1.12 倍
**假设九成的活儿能并行、一成必须串行,那么核数无穷大时加速比也只有 10 倍。**
**但核数每翻一倍,多出来的那点越来越小**——
**最后几行翻倍只多一成多,说明大头已经被串行部分吃掉了。**
**所以要提速,先想办法把【串行那一成】弄小,而不是加机器。**
第一张表在四核处拐平:20/10/5/5/5。不是调度器偷懒,是没活可派。 第二张表是理论曲线,注意最后一列【比上一行快多少】在递减:1.82 → 1.69 → 1.53 → 1.36 → 1.22 → 1.12。越往后越不划算。 两张表合起来说的是同一件事:加速的上限由【能并行的比例】决定,不由你买了多少核决定。 所以【加机器】永远应该是最后一步,前面该做的是:拆任务、减少共享、把串行部分压小。
30 秒实验
- 把任务数改成 8、核数取 4,看加速比是不是掉到 2 倍左右。
grep -c processor /proc/cpuinfo看你机器几个核,再想想你的常用程序能用满吗。time一个你自己的多线程程序,看 user 时间是不是超过 real 时间——超过了才说明真并行。
常见误区
- 【核越多越快】。受并行度限制。任务数少于核数时,多出来的核完全没用。
- 【加速比不到线性说明调度器不行】。多半是任务本身不能拆,或者有共享资源。先看程序,再怀疑系统。
- 【所有程序都值得改成并行】。要看【频率 × 单次耗时】。低频短任务改成并行,只会换来一堆同步 bug。
自测三问(点开对答案)
1. 四个各 5 拍的活儿,为什么从四核开始总耗时不再下降? —— **只有四个任务,第五个核没活可派。**加速上限由任务并行度决定。 2. 怎么快速判断一个程序能不能吃多核? —— 看 `top` 里它的 CPU 占用能不能超过 100%。**不能就是单线程的,加核无效。** 3. 什么时候【值得】把程序改成并行? —— 看**频率 × 单次耗时**:跑得越勤、单次越久越值得。低频短任务改了不划算。- ☐ 4.15 吞吐量与延迟
相关笔记
- 实验方法 — 量这些数的方法
- 吞吐量与延迟 — 多核下的取舍
- 思考 — 从加速比反推瓶颈
- 🐧 Linux是怎样工作的 · 索引