Perl 42:并行聚合与测量边界
原定 E06 的并行 worker 不是“两个进程同时写文件”。LogTool::Course::Parallel::parallel_rows 先把输入记录按下标分片,最多启动 8 个 worker,且 worker 数不会超过记录数。每个 worker 在子进程里使用 aggregate_rows 生成自己的 level 计数,再通过 pipe 回传 Storable::freeze 后的行数组。父进程只接受最多三行、level 限定为 ERROR/INFO/WARN、count 为非负整数的 payload;这就是“受控三等级聚合”的有界数据面。
父进程等待所有 worker 后再合并。任何 worker 非零退出、信号终止、pipe 关闭失败或 payload 解码失败,都会得到 worker failed,publish_parallel_report 不调用 save_report。t/course-engineering.t 先把目标写成 OLD\n,再注入一个会失败的 worker,断言旧文件未变;这覆盖“任一失败不发布部分结果”。若在 fork 或 pipe 创建中途失败,已启动的 child 会被等待回收,避免把孤儿 worker 留给后续测试。
并行结果还必须和串行结果相同。测试用同一组记录比较 parallel_rows($records, 2)、parallel_rows($records, 8) 与单进程 Aggregator 的 rows,证明过量 worker 会被输入规模收敛,排序仍由最终合并统一完成。这里没有把 worker 的 STDERR、任意外部程序输出或大 payload 纳入协议;它只是课程用的固定聚合器,不是通用进程池。
原定第 35 章的性能测量也补到独立进程。experiments/course-performance.pl --mode naive|aggregator 分别运行多次扫描计数和单遍 Aggregator,输出相同 TSV 的 SHA-256。tools/course-performance-probe.py 只用 Python 标准库 fork、exec、wait4 和 resource 启动两个独立 Perl 进程,记录 wall time、ru_maxrss、退出码、信号、STDERR 和输出 SHA 是否相等。本机样本显示两种策略 SHA 相同,RSS 数字来自平台 ru_maxrss 单位。
这些数字仍不是普遍性能结论。当前输入只有 5000 条合成记录,进程启动开销占 wall time 很大;macOS 与 Linux 对 ru_maxrss 单位定义不同;一次样本不能说明分布,也不能证明并行一定更快。课程可声称的是:同一输出先被哈希校验,再记录耗时和峰值 RSS 口径;优化讨论不能跳过等价性检查,也不能把一个平台的一次值推广到所有数据量。
练习:如果 worker 成功写出一半 payload 后被信号杀死,父进程能否发布剩余 worker 的结果?不能。协议要求所有 worker 都成功,且每份 payload 都能解码并通过行形状检查;任一失败时只能保留旧报表。官方来源为 Perl 5.38.2 pod/perlfork.pod、pod/perlipc.pod、pod/perlfunc.pod 的 fork/pipe/waitpid,核心 Storable 文档,以及 Python 标准库 resource/os.wait4 文档;证据见 t/course-engineering.t、experiments/course-performance.pl 和 tools/course-performance-probe.py。









