和风网标志

您对 Bash 管道的思维模型是错误的吗?

日期:

[迈克尔·林奇]遇到了一个奇怪的情况。 为什么编译然后运行他的程序将近 10 倍 而不是仅仅运行程序本身? [Michael] 在对一个编程项目进行基准测试时遇到了这个问题,将其简化为可重复性和分析的基本要素,并发现它突出显示了 bash 管道如何工作的错误思维模型。

情况是这样的。 [Michael] 的精简程序所做的第一件事就是启动一个计时器。然后它只是读取并计算一些字节 stdin,然后打印出发生这种情况需要多长时间。按如下方式运行测试程序时,大约需要13微秒。

$ echo '00010203040506070809' | xxd -r -p | zig build run -Doptimize=ReleaseFast
bytes: 10
execution time: 13.549µs

当直接运行(已编译的)程序时,执行时间会增加到 162 微秒。

$ echo '00010203040506070809' | xxd -r -p | ./zig-out/bin/count-bytes
bytes: 10
execution time: 162.195µs

再说一遍,两者之间的唯一区别 zig build run./zig-out/bin/count-bytes 是首先编译代码,然后立即运行它。第二个只是运行编译后的程序。

如何添加额外的编译步骤 减少 执行时间?事实证明,[Michael] 关于 bash 管道如何工作的心智模型是不正确的,而且他在这方面做得很好 解释它们实际上是如何工作的,以及为什么会导致奇怪的行为 他看到了。

简而言之,bash 管道中的命令不是按顺序启动的。它们都是同时启动并并行执行的。这意味着当直接运行时,[Michael] 的字节计数器程序立即启动。然后它等待了大约 150 微秒,什么都不做,而 echo '00010203040506070809' | xxd -r -p 管道的一部分开始传递数据供程序读取。这就是运行已编译版本时额外执行时间的来源。

那么为什么先编译它运行得更快呢?基本原因相同:当 zig build run 命令启动,它首先花费一点时间编译程序。然后,当编译后的程序实际启动(并开始执行计时器)时,来自 bash 管道的输入数据已经准备好。因此,新编译的程序执行时间更短,因为它不会等待管道中较早的数据变得可用。

这是对 bash 管道在幕后如何实际运行的有趣观察,我们对 [Micheal] 在整个过程和解释中提供的细节感到高兴。迟早,像这样的细节会突然出现并引起一些人的眉毛,就像发现的用户一样 ssh 命令中有关空格的麻烦边缘情况.

现货图片

最新情报

现货图片