我经常需要将一堆文件打包成 tar 文件,用 gpg 加密,然后压缩。这是在 Linus VPS 服务器上,因此内存比执行速度更重要(我真的不关心执行速度)。
如果我将这三个步骤作为一个命令执行(tar | gpg | bzip2 > output.tar.gpg.bzip2),这会比先调用 tar,然后调用 gpg,然后调用 bzip2 消耗更多的内存吗?
这些文件可能非常大(数百兆字节/千兆字节)
答案1
同时运行的程序越多,所需的内存就越多。但这是一种权衡,使用管道而不是单独运行每个程序往往需要更少的磁盘空间。您只需要存储初始输入和最终输出。如果您通过 ssh 或类似方式将数据存储在其他地方,那么除了输入文件之外,您甚至可能不需要初始磁盘空间。使用管道的另一个特点是,任何阶段的数据处理速度都不会比管道中最慢的阶段更快。
GnuPG 使用的 OpenPGP 格式本身支持压缩。压缩发生在加密之前,因此比加密后压缩更安全、更高效。此外,解密时会自动检测压缩,因此您不必担心将其添加到管道中。与运行单独的压缩程序相比,它所需的内存也更少。GnuPG 支持 Zip、Zlib (Gzip) 和 Bzip2 压缩。
答案2
当你这样做时(tar | gpg | bzip2 > output.tar.gpg.bzip2
)你管道 命令,这意味着您同时运行所有命令,并将每个命令的输出重定向到以下命令的输入(直到您将最后一个输出重定向到文件中)。因此,tar
输出进入gpg
输入,输入输出到bzip2
输入,最终输出到文件中。
因此,当您使用管道时,您会使用更多内存,因为您同时运行所有命令。您还会使用更多处理能力,因为gpg
和bzip2
是两个耗 CPU 的程序。
答案3
您应该检查 bzip2 是否对大小做了一些有价值的事情,pgp 数据最终看起来像一个(完全)随机流,因此实际上不应该是可压缩的。
答案4
所有这些命令:tar
、bzip2
和gpg
都以流式方式工作:它们获取一块数据(比如说 1 兆字节),对其进行转换并将其推送到下一阶段。之后,RAM 将被重新用于处理另一块数据。因此,即使您要处理 1 TB 的数据,也会逐块进行处理。
现在,当您tar
单独调用 tar 时,它会按如下方式工作:从磁盘读取一个数据块,用归档所需的一些标头包装它,将其推送到磁盘,然后将其忘掉。然后重复。然后重复。在此过程中,您永远不需要 RAM 中的多个数据块。我不知道tar
缓冲区有多大,但可能只有几兆字节。因此,您只需要几兆字节的 RAM 即可使其工作。
gpg
并bzip2
以相同的方式工作。gpg
获取一小块数据,对其进行加密并向前推进——所有操作都在一个循环中完成。bzip2
获取一小块数据,对其进行压缩并向前推进——所有操作都在一个循环中完成。
如果您不使用管道来调用这些命令,则需要的 RAM 会更少:您只需要同时在 RAM 中保留一个数据块。使用管道时,数据块会从一个命令传递到另一个命令,并将其保留在 RAM 中:您需要几个数据块:一个用于tar
,一个用于gpg
,一个用于bzip2
。因此最多需要几兆字节。您不需要 RAM 来一次存储所有数据。
使用流水线技术,您实际上可以获得另一个好处:速度。您不需要在磁盘上存储临时数据。数据块仅使用 RAM 来回传递。tar
比较bzip2
:3GB 数据、tar 文件中的 3GB 数据、tar.bzip2 文件中的 1GB 数据、tar.bzip2.gpg 文件中的 1GB 数据。即使您不同时存储它们(例如在此过程中删除源文件),您仍然需要比管道版本多将 4GB 的数据写入和读取到磁盘。而且 VPS 的磁盘操作通常很慢,因此管道可以为您节省大量时间。bzip2
gpg
(注意:这个解释是简化的。所有这些命令都会在 RAM 中保存一些额外的数据,但这并不重要。此外,您通常可以在特定命令中更改缓冲区的大小。)