我一直在尝试了解在 Linux 中执行以下命令时涉及的执行和内部数据结构和算法。
bzip -dc mybig.bz2 | cut -d ',' -f 1,2,4,5,9,10,12 | sort > output_file
- 当您将一个程序的输出通过管道传输到另一个程序时,中间结果存储在哪里?
- 当我们有类似 sort/uniq 的命令通过管道接受来自前一个命令的输入时,sort 是否能够与 bzip2 并行工作,
sort
是否可以在不同时获得所有输入的情况下进行排序? - 由于 sort(gnu-coreutils) 在内部执行合并排序,执行期间合并排序的中间结果在哪里,假设文件
mybig.bz2
的大小为 20GB,排序如何管理所有如此巨大的文件在磁盘中的中间结果?
- 当我们有类似 sort/uniq 的命令通过管道接受来自前一个命令的输入时,sort 是否能够与 bzip2 并行工作,
- 您如何比较以下两个不同 shell 脚本的 I/O 操作数、中间文件大小和 cpu 使用率(我正在寻找更多的理论推理而不是基准测试结果)?
使用重定向和中间文件。
bzip -dc mybig.bz2 > temp1
cut -d ',' -f 1,2,4,5,9,10,12 temp1 > temp2
sort temp2 > output_file
使用管道。
bzip -dc mybig.bz2 | cut -d ',' -f 1,2,4,5,9,10,12 | sort > output_file
是否有更好的方法使用 shell 执行此操作,其中 cat
、cut
和 sort
并行运行(行缓冲)并且最少的磁盘 I/O 和 cpu 周期?
非常感谢任何帮助。
最佳答案
使用重定向和中间文件
bzip -dc mybig.bz2 > temp1
cut -d ',' -f 1,2,4,5,9,10,12 temp1 > temp2
sort temp2 > output_file
让我们假设 mybig.bz2 为 1 GB,未压缩版本为 10 GB。然后上面将:
- 读取 1 并写入 10 (bzip2 -> temp1)
- 读取 10 并写入 10(剪切,我们假设剪切大小基本相同)
- 读取 10,写入 10,读取 10 和写入 10(排序使用临时文件进行大排序)。
总磁盘 I/O 为 1+10+10+10+10+10+10+10 = 71 GB。
使用管道
bzip -dc mybig.bz2 | cut -d ',' -f 1,2,4,5,9,10,12 | sort > output_file
给你:
- 读取 1 GB(bzip2 - 数据未写入磁盘)
- 不从磁盘读取任何内容(cut 将所有内容保存在内存中)
- 写入 10 GB,读取 10 GB 并写入 10 GB(首先从内存中排序读取,然后保存到磁盘上的临时文件,读回并写入输出)
总磁盘 I/O 为 1+10+10+10 = 31 GB。
使用管道不会浪费任何东西。相反,如果 bzip2 与排序速度相同,则可以保持 2 个 CPU 并行运行。较新版本的排序还支持“--parallel=N”以在多个 CPU 上分配排序。
如果排序后的数据压缩的很好,还可以使用--compress-program=PROG
来压缩临时文件。如果您有 CPU 闲置,这将非常有用。根据闲置的 CPU 数量,您可以使用“pzstd”、“pigz”、“pbzip2”、“pxz”。它们具有不同级别的压缩(从低到高)。
通过这种方式,您可以将磁盘 I/O 从 31 GB 降低到 1+1+1+10。
管道中的中间结果不会存储在任何地方。相反,它一写入就被读取。两个进程之间只有一个小缓冲区(通常在 4-128 KB 的数量级)。当缓冲区已满时,写入进程将阻塞,直到读取进程从缓冲区中读取内容。这种技术可以在具有 1 GB RAM 和 100 GB 磁盘的系统上处理 1 TB 数据 - 只要数据在存储在磁盘上时经过压缩。
关于linux - 当输入通过管道或重定向到它时,sort/uniq 命令的内部工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43602042/