← 揭开黑盒:理解系统的调查课堂

第二章 · 计算机选择的数学 / 第七单元 · 一起计算的条件

把计算交出去之前

我们把矩阵结果按行分配给几个 Worker。每个人知道自己的起止行,算完交回;主页面按位置拼成完整 C。这个方案能运行,但是否值得,需要真实测量。

预计用时:45 分钟。打开 真实计时。从发布后的网页进入,或在下载包 assets/math-lab/ 中运行 py -3 lab.py;直接用文件协议打开时,浏览器可能拒绝 Worker。

先规定谁拥有哪个结果

边长 5,分给两个执行者,教材生成的行区间为 [0,2) 与 [2,5)。左边包含、右边不包含,因此分别算 0、1 行和 2、3、4 行。不能整除的余数也有归属。

每个 Worker 接收完整 A、B 以及 n、start、end,只返回自己负责的 (end−start)*n 个输出。主页面检查行范围与长度,再放回 start*n 开始的位置。没人需要同时修改同一个输出格子,因而这个分解省掉了共享 C 的写入竞争。

这是算法选择带来的协调简化。若改成按 k 分工,各 Worker 返回的是同一批格子的部分和,主页面就需要额外归约,并重新考虑加法顺序。

数据怎样过去,又怎样回来

主页面通过 postMessage 向每个 Worker 发送输入。当前实现让浏览器复制 A、B;它没有共享同一块输入内存。结果则把新建的输出缓冲转移回来,Worker 不再拥有可用的该缓冲区。

完整输入重复复制会占时间和内存。它让本课的边界易于检查,也可能很低效。可复用 Worker、共享内存、只分发需要的行等方案,都会改变成本与程序约定,适合后续改造。

这次到底在测什么

先写预测,再选择边长 48,点击“测 1 / 2 / 4 个 Worker”。每种数量各做三次,轮换先后。每轮都新建 Worker,计时覆盖启动、脚本加载、输入复制、计算、回传和结果拼接;参考核对在计时之外。

这里的 1 个 Worker 也是完整往返。因此可以比较“按当前启动协议多开几个 Worker”是否获益。它与主线程已经预热的函数调用具有不同边界,两张表中的毫秒数不能直接用来声称“并行内核加速了多少”。

后台调度与设备能力影响这些结果。即使浏览器报告很多逻辑处理器,也不等于全部资源都可用,更不意味着线程数等于物理核心数。

用变化检验解释

两个合理的候选解释是:“计算可以并行,所以更多 Worker 应该更快”;“启动与复制可能占主导,小输入还不值得分工”。先只增大 n,观察差别是否变化。若始终没有加速,把这个结果保留下来。

下一步改造可以复用 Worker。届时必须同时保留“首次启动”和“已就绪后的往返”两种测量范围,否则只是悄悄把不利部分移出了计时器。

故障也要有结果:Worker 错误、返回格式不符或超时,当前界面会标记本次未完成,并终止本轮创建的 Worker。它不会把缺失的行填成零后展示“更快”。错误记录也可以导出。

第七单元交付

提交至少两个规模的往返样本,附一张行区间图。说明计时包含什么,为什么输出没有写入竞争,以及一个可能改变排名的实现调整。

验收时,把 n=5、执行者数量=4 的范围写出来,确认每一行恰好有一个归属;再解释为什么本章没有通过这个 CPU 实验测量 GPU 性能。若只能说明“线程更多”,还需要回到输入和输出的实际路径。

至此,数、搬运与并行三个完整单元可以一起回看。进入 综合代码解析Ⅱ,之后继续向规模与表示的选择推进。