通过bash管道处理大文件,它会缓冲吗?

通过bash管道处理大文件,它会缓冲吗?

我需要使用如下命令:

$ cat large.input.file | process.py > large.output.file

问题是,这样硬盘在读取输入文件和写入输出文件之间切换会不会很困难?

有没有办法告诉 bash 在执行这种管道时使用大的内存缓冲区?

答案1

别担心。操作系统会帮你缓冲,而且通常做得非常好。

话虽如此:如果您可以更改 process.py,那么您就可以实现自己的缓冲。如果您无法更改 process.py,那么您可以编写自己的 buffer.py 并像这样使用它。

$ cat large.input.file | buffer.py | process.py | buffer.py > large.output.file

可能更容易的是阅读和写作形式RAM 磁盘

答案2

操作系统会将输出缓冲到一定量,但如果输入和输出文件都在同一个驱动器上,则仍可能会出现大量的头部翻转,除非您自己process.py进行一些缓冲。

您可以cat在您的示例中替换为管道查看器 (pv)(在大多数标准存储库中可用,并且如果它不在您的发行版存储库中,则可以轻松编译)允许您将其设置为缓冲更多(使用-B/--buffer-bytes选项)并显示进度条(除非您要求它不显示),如果您process.py不输出自己的进度信息,这对于长时间操作可能非常方便。对于将数据从驱动器上的一个位置传递到同一驱动器上的另一个位置,这可能会产生很大的不同,除非整个过程主要是 CPU 绑定而不是 I/O 绑定。

因此对于 1Mb 缓冲区你可以执行以下操作:

pv -B 1m large.input.file | process.py > large.output.file

我一直用pv这种东西,虽然主要是为了进度指示器而不是可调整的缓冲区大小。

另一种选择是使用更“标准”的(标准是指默认情况下通常可用的标准,其命令行格式与大多数常用命令略有不同)dd,尽管它没有进度条功能:

dd if=large.input.file bs=1048576 | process.py > large.output.file

编辑:ps. 吊坠可能会指出,cat在您的示例中不需要这样做,因为下面的方法同样有效,并且效率会略高一些:

process.py < large.input.file > large.output.file

有些人将删除不必要的电话称为cat“消音”,这些人可能不应该受到鼓励......

答案3

有没有一种古老的 unix 工具叫做“缓冲区”?虽然今天的缓存技术并不需要这个工具 - 但是它确实存在。

答案4

尝试使用我刚刚编写的这个 Python 2 小型程序:

#! /usr/bin/python2
# This executable path is Gentoo-specific, you might need to change it yourself

import sys;

if sys.argv[1].endswith('K'):
   bytestoread = int(sys.argv[1].translate(None, 'K')) * 1024;
elif sys.argv[1].endswith('M'):
   bytestoread = int(sys.argv[1].translate(None, 'M')) * 1024 * 1024;
elif sys.argv[1].endswith('G'):
   bytestoread = int(sys.argv[1].translate(None, 'G')) * 1024 * 1024 * 1024;

while True:
   buffer = sys.stdin.read(bytestoread);
   if buffer == '':
      exit();
   sys.stdout.write(buffer);
   buffer = None;   # This one is for making sure the read buffer will get destroyed, otherwise we could bring our system to a halt if we have 8 GB of RAM, request a 5 GB buffer, and it ends up eating 10 GB of memory.

要使用这个文件,请像这样调用它:

cat large.input.file | process.py | buffer.py 2G > large.output.file

您可以使用 2K 来指定 2 千字节,2M 来指定 2 兆字节,2G 来指定 2 千兆字节,如果您愿意,可以添加 2T 来表示 2 兆兆字节的缓冲区:3

在使用 压缩虚拟机映像时,我总是遇到这个问题pigz -1,因为这使得压缩速度非常快,磁盘开始同时读取和写入,并且当磁盘磁头开始在输入和输出文件之间快速移动时,该过程会减慢直至停止。所以我做的是制作这个小程序,从标准输入读取大量数据,将其写入标准输出,然后重复。当读取返回空白字符串时,这是因为没有收到更多标准输入并且脚本已完成。

相关内容