我正在处理一些大型压缩文件,发现一些有趣的东西,我不明白使用 cat+pv+zcat 比单独使用 zcat 更快。
为此,我使用 1gb 压缩的 json 作为测试。
time cat test.json.gz > /dev/null
time zcat test.json.gz > /dev/null
time cat test.json.gz | zcat > /dev/null
time cat test.json.gz | pv | zcat > /dev/null
real 0m8.245s
real 0m33.075s
real 0m30.504s
real 0m26.682s
同样,写入文件时:
time cat test.json.gz > t0.json.gz
time zcat test.json.gz > t1.json
time cat test.json.gz | zcat > t2.json
time cat test.json.gz | pv | zcat > t3.json
real 0m21.053s
real 0m59.011s
real 0m57.110s
real 0m54.439s
我还尝试以相反的顺序运行测试,看看是否有一些缓存使后续运行速度更快,但得到了相同的结果。我检查过,输出文件是相同的。
一般来说,我认为管道中的多个步骤会增加处理文件所需的时间,那么为什么添加 pv 会加快速度呢?它是否有某种内置的并行化发生? 这是怎么回事?
如果这是预期的行为,那么我只是偶然发现了一种非常简单的方法,可以将处理速度提高 10%,但我很想了解发生了什么。
一般来说,我认为管道中的多个步骤会增加处理文件所需的时间,那么为什么添加 pv 会加快速度呢?它是否有某种内置的并行化发生?这是怎么回事?
在多核处理器上,至少有时您可能会获得真正的多进程并发。 即使您没有获得真正的并发性,多处理确实是并行处理的一种形式,所以是的,存在一些并行化。
更有可能的是,
zcat
本身运行单线程,在读取输入、解压缩和写入输出之间交替。 所有 I/O 往往都很慢,但文件 I/O 可能会比通过管道的 I/O 慢。因此,通过管道向其提供输入而不是依赖它从文件中读取,可以提高 zcat
本身的性能。
当然,某些进程仍然需要读取该文件,但可以想象,
zcat
的解压+输出I/O比(比如说)cat
的文件I/O+管道I/O成本更高。 在这种情况下,使用 cat | zcat
进行多处理可能会取得胜利。
更神秘的是,为什么将
pv
插入到 cat
和 zcat
之间的管道中可能会被观察到可以提高性能,但我的猜测是 pv
一次缓冲的数据比 cat
多,所以由于 pv
位于中间,因此 zcat
总体上可以以更少的读取次数读取数据,每次读取的数据都更大。 这也是潜在的性能胜利。 pv
的管道 I/O + 分析 + 管道 I/O 至少与 cat
的文件 I/O + 管道 I/O 一样快,因此 pv
很可能没有任何速度,这是完全合理的。对整个管道执行的挂起时间产生固有的不利影响。