管道,它们如何工作?

时间:2014-07-17 15:18:50

标签: python multiprocessing pipe

我正致力于优化需要解析大量(12 TB)数据量的Python脚本。目前,它基本上看起来像:

gzip -d -c big_file.gz | sed /regex|of|interesting|things/p | script.py 

(实际上,管道是由subprocess.Popen完成的,但我不认为这很重要 - 如果我错了,请纠正我。)

gzip->sed->python管道似乎是目前最耗时的部分。我假设这是因为这里有三个独立的进程:因为它们都没有共享地址空间,所以需要在它们之间传递的任何信息实际上都要从一个复制到另一个,所以这三个管道导致总共最多36 TB被推入我的RAM,而不仅仅是12。

我是否正确理解了发生了什么?

2 个答案:

答案 0 :(得分:3)

让我们先进行一点测试:

time dd if=/dev/zero of=/dev/null bs=2M count=5000
time dd if=/dev/zero bs=2M count=5000 > /dev/null
time dd if=/dev/zero bs=2M count=5000 | cat > /dev/null
time dd if=/dev/zero bs=2M count=5000 | cat | cat | cat | cat | cat > /dev/null

结果:

5000+0 records in
5000+0 records out
10485760000 bytes (10 GB) copied, 0.651287 s, 16.1 GB/s

real    0m0.653s
user    0m0.000s
sys     0m0.650s
5000+0 records in
5000+0 records out
10485760000 bytes (10 GB) copied, 0.585887 s, 17.9 GB/s

real    0m0.587s
user    0m0.007s
sys     0m0.580s
5000+0 records in
5000+0 records out
10485760000 bytes (10 GB) copied, 8.55412 s, 1.2 GB/s

real    0m8.556s
user    0m0.077s
sys     0m9.267s
5000+0 records in
5000+0 records out
10485760000 bytes (10 GB) copied, 9.69067 s, 1.1 GB/s

real    0m9.692s
user    0m0.397s
sys     0m25.617s

添加单个管道会大大降低性能;添加多个管道会略微降低性能。多次运行结果似乎一致。

当我有更多时间时,我需要更多地研究为什么,我的猜测是cat进程使用小缓冲区读取数据,因此dd进程写得慢。
有一个名为bfr的程序旨在解决这个问题;我从来没有尝试过。最后更新是从2004年开始......

你也可以尝试实施gzip& Python字符串替换。很难预测性能增益是否值得花时间,但是......

答案 1 :(得分:2)

管道可能不是你的问题。 Modern PCs can copy memory at rates of 70GB/s

如果您想知道第一阶段需要多长时间,请运行:

 time gunzip big_file.gz | sed '/regex|of|interesting|things/p' > /dev/null

这将解压缩数据并对其进行过滤,然后告诉您需要多长时间。

我的猜测是糟糕的Python脚本获取太多数据并使用Python处理大量数据只需要时间。

[编辑] 我刚才注意到了一些事情:Python文档说:

  

bufsize(如果给定)与内置open()函数的对应参数具有相同的含义:0表示无缓冲[...] bufsize的默认值为0(无缓冲)。

在创建管道时尝试使用bufsize=-1bufsize=102400

从中获取的教训:缓冲管道很快,无缓冲管道很慢。