【问题标题】:Parallel zipping of a single large file并行压缩单个大文件
【发布时间】:2021-07-03 10:56:42
【问题描述】:

有没有办法在 Java 中进行并行压缩?

我目前正在使用ParallelScatterZipCreator,但不幸的是它对每个文件进行并行压缩。因此,如果有一个文件比其他文件大得多,则并行压缩只发生在较小的文件上。然后它必须等到大文件被串行压缩。

是否有更好的库可以利用所有 CPU 内核,即使我们压缩单个文件也是如此?

【问题讨论】:

    标签: java multithreading parallel-processing zip


    【解决方案1】:

    TL;DR:您可能根本不需要压缩。如果你这样做了,那么你可能不想使用 zip 格式,它是过时的技术,有相当大的缺点,显然你有一些相当具体的需求。您可能需要 ZStandard (zstd)。

    压缩是如何工作的

    压缩的工作原理是查看一个字节块并在其中找到某种形式的重复。因此,无法压缩单个字节。

    这使得这项工作从根本上与并行化不一致:如果您采用 100 万字节的 blob 并将其压缩为 10 个 100k 字节的块,分别压缩每个 miniblob,然后任何重复,其中一个重复在一个 miniblob 中,另一个在另一个 miniblob 中,意味着您错过了压缩数据的机会,如果您将这些数据压缩到一个 blob 中,您将不会错过。

    ZIP确实让你稍微并行化的唯一原因是因为它是一种旧格式 - 在当时是明智的,但在这个时代,ZIP 格式的几乎每个部分都是垃圾.

    为什么 ZIP 不好?

    ZIP 好坏参半,将两个不相关的工作混为一谈。

    1. 捆绑器。捆绑工具是一些软件,它获取一堆文件并将其转换为单个流(单个字节袋)。为此,捆绑工具将获取有关文件的元数据(其名称、其所有者/组或其他访问信息、其最后修改时间等)以及其中的数据,并将其序列化为单个流。 zip 这样做,例如posix tar 工具。

    2. 压缩机。压缩器获取数据流并通过查找重复模式对其进行压缩。

    zip 本质上只是#1,但作为捆绑程序的一部分,带有“此文件中的数据”的部分有一个标志,表明压缩算法已应用于表示数据的字节。理论上您几乎可以使用任何算法,但在实践中,每个 zip 文件都有所有 条目使用 DEFLATE 算法压缩,这远不如更现代的算法。

    .tar.gz 是完全相同的技术(首先捆绑它:tar 文件,然后 gzip 该 tar 文件。gzip 是 DEFLATE 算法),但在某些情况下效率更高(它将压缩应用于整个流而不是重新启动每个文件都从头开始。如果你拿 1000 个类似的小文件,那么 .tar.gz 格式的文件比 .zip 格式的文件小几个数量级。

    此外,zip 是旧的,它在当时做出的选择是可辩护的,但在现代系统中却很愚蠢:您不能“流式传输”zip(在收到整个文件之前,您无法有意义地开始解压),因为捆绑器的信息位于文件的末尾

    那么为什么我可以并行化 zip?

    因为 zip 会在每个文件上“重新启动”压缩窗口。这是低效的,并且会损害 zip 文件的压缩率。

    如果需要,您可以将完全相同的原则应用于任何数据块。用压缩效率换取并行性。 ZIP 是一种没有用处的格式;正如你所说,如果你有一个大得多的文件,那就没有意义了。

    'restart window at' 是一个可以推广的原则,并且各种压缩格式以更有用的方式支持它(每 X 个字节重新启动,而不是 ZIP 不可靠的'在每个文件处重新启动')。

    什么是瓶颈?

    发送数据涉及多个方面:源提供您要发送的字节的速度,字节被处理成然后可以发送的包的速度(例如zip工具,但可以任何东西,包括只是逐字发送,未压缩),打包字节传输到目标系统的速度,目标可以解压它的速度,以及目标可以处理解压结果的速度.

    您确定压缩方面是瓶颈吗?

    在基本情况下,您从硬盘读取字节,压缩它们,通过住宅互联网管道将它们发送到另一个系统,该系统解压缩并将它们保存在 HDD 上,很可能是瓶颈是网络。并行化压缩步骤完全是一种浪费,实际上只会通过降低压缩率来减慢速度

    如果您是从旋转盘片读取文件,那么源的速度可能是瓶颈,并且并行处理会大大减慢速度:您现在要求读取头弹跳,这比一次性顺序读取数据要慢很多

    如果你有一个快速的源和一个快速的管道,那么瓶颈无疑是压缩和解压缩,但解决方案是根本不压缩:如果你正在传输数据SSD 或从连接 USB3 的字节喷射传感器通过 10M CAT6 电缆将其从一个千兆以太网端口传输到另一个,那么为什么要压缩呢?只需发送这些字节。压缩不会让它变得更快,只要你不使那个 1Gb 连接饱和,你尝试压缩它绝对没有任何收获。

    如果您的管道速度较慢,那么让事情变得更快的唯一方法就是尽可能多地压缩。其中最肯定涉及不使用 DEFLATE 算法(例如,不要使用 zip)。使用另一种算法并对其进行配置以获得更好的压缩率,但代价是 CPU 性能。并行化是无关紧要的;这不是瓶颈,所以这样做没有任何意义。

    结论

    您很可能希望通过未压缩的方式发送文件,或者通过 ZStandard 发送您的文件,根据需要调整压缩与速度的比率。我不知道 java 本身有任何 ZStandard (zstd) impl,但 zstd-jni 项目为您提供了一个基于 java 的 API 来调用 C zstd 库。

    如果您坚持使用 ZIP,答案是相当基本的“不,您不能真正做到这一点”,尽管理论上您可以编写一个压缩能力更差但并行性更好的并行 ZIP 压缩器(通过重新启动窗口除了在每个文件上强制重新启动之外,在单个文件中用于更大的文件),并生成仍然与地球上几乎所有解压缩工具兼容的 ZIP 文件。我不知道有一个,我不认为存在一个,而自己编写一个绝对不是微不足道的练习。

    【讨论】:

    • 感谢您的详细回复。确实 zip 不好,但不幸的是我们的客户需要 zip 格式。您可能是对的,没有可以做到这一点的 zip 库,但可以希望。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-07-02
    • 2017-03-15
    • 2022-01-19
    • 1970-01-01
    • 2011-12-12
    • 2021-03-22
    • 1970-01-01
    相关资源
    最近更新 更多