单个大文件的并行压缩

4

有没有一种方法可以在Java中进行并行压缩?

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

是否有更好的库可以利用所有CPU核心,即使我们正在压缩单个文件?

1个回答

3
TL;DR: 你也许不需要压缩。如果需要,那么你可能不想使用zip格式,因为它是过时的技术并且有一些相当特定的需求。你可能想要使用ZStandard (zstd)。
压缩通过查找字节块中的重复形式来工作。因此,单个字节无法进行压缩,这使得任务与并行化根本不一致。如果将100万个字节的字节块分成10个大小为100k字节的小块进行压缩,则任何在一个小块中重复出现的内容与另一个小块中重复出现的相同内容,都意味着你错过了一个压缩数据的机会。唯一的例外是ZIP可以部分并行压缩,这是因为它是一个老格式,在现代系统中几乎每个部分都很糟糕。
ZIP存在问题的原因是它混淆了两个不相关的任务。第一个任务是打包工具,第二个任务是压缩器。打包工具是一些软件,将许多文件转换成单个流(一堆字节)。压缩器则通过查找重复模式来压缩数据流。zip实质上只是第一个任务,但是作为打包工具的一部分,“该文件内的数据”部分有一个标志,指示已将压缩算法应用于表示数据的字节。理论上,你可以使用任何算法,但实际上每个zip文件都使用DEFLATE算法压缩所有条目,这远不如更现代的算法。与之相似的是.tar.gz格式,但在某些情况下效率更高(它对整个流应用了压缩而不是为每个文件从头开始压缩)。此外,zip是过时的,并且它在当时做出了可辩解的选择,但在现代系统中变得愚蠢:你无法“流式传输”zip文件(直到整个文件被接收完毕才能有意义地开始解压缩),因为打包工具的信息在文件结尾处。如果需要,建议使用ZStandard (zstd)。

为什么我能够并行化压缩zip文件?

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

如果需要的话,你可以将相同的原则应用于任何数据块。牺牲压缩效率以实现并行处理。ZIP格式不会以有用的方式执行此操作;正如你所说,如果只有一个更大的文件,则无意义。

'重新启动窗口'是一种可概括的原则,各种压缩格式支持以更有用的方式进行(每X字节重新启动,而不是ZIP的不可靠的“每个文件重新启动”)。

瓶颈是什么?

发送数据涉及多个方面:源提供要发送的字节的速度、将字节处理为可发送的包的速度(例如zip工具,但可以是任何内容,包括直接发送未压缩的数据),打包字节传输到目标系统的速度、目标系统解包的速度以及目标系统处理解包后结果的速度。

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

在基本情况下,从硬盘读取字节,将其压缩成zip格式,通过住宅互联网管道发送到另一个系统,该系统解压缩并将其保存在硬盘上,很可能瓶颈是网络。并行化压缩步骤是完全浪费的,事实上只会通过降低压缩比而减慢速度

如果你从旋转盘中读取文件,则速度较慢的源很可能是瓶颈,而并行处理大大减慢速度:现在你要求读头来回跳动,这比一次顺序读取数据要慢得多

如果你有快速的源和高速的传输管道,那么瓶颈无疑是压缩和解压缩,但解决方案不是压缩:根本不需要压缩:如果你正在从SSD或USB3连接的字节喷出传感器中传输数据,并将其从一个千兆以太网口传输到另一个千兆以太网口的10M CAT6电缆上,则为什么要进行压缩?只需发送这些字节即可。压缩不会使传输速度更快,只要不饱和1Gb连接,尝试对其进行压缩就完全没有任何收益。

如果你的传输管道速度很慢,那么使它更快的唯一方法就是尽可能多地压缩。这绝对不涉及使用DEFLATE算法(例如不要使用zip)。使用另一种算法,并将其配置为获得更好的压缩率,以牺牲CPU性能。并行化是无关紧要的;它不是瓶颈,因此完全没有必要这样做。

结论

很可能您希望以未压缩的方式发送文件,或者使用ZStandard对文件进行压缩,并根据需要调整压缩与速度之间的比率。我不知道Java本身是否有任何ZStandard(zstd)实现,但是zstd-jni项目为您提供了一个基于Java的API,可调用C zstd库。

如果您坚持使用ZIP,则答案是相当基本的“不行”,尽管您可以理论上编写一个并行ZIP压缩器,其压缩能力更差但并行性更好(通过在单个文件中重启窗口以处理较大文件,并在每个文件结束时执行强制执行的重新启动),并且生成的ZIP文件仍然与全球几乎所有解压工具兼容。我不知道有没有这样一个压缩器,我认为没有,自己编写会是一个明显不简单的练习。


感谢您详细的回复。确实,zip格式并不好,但不幸的是我们的客户要求使用zip格式。您可能是对的,没有zip库可以做到这一点,但人总是会抱有希望的。 - Saeid Nourian
这个答案在很多方面都是错误的,包括但不限于:1. “这项工作与并行化根本相矛盾”-至少对于zip来说是错误的:使用deflate将数据压缩回流时,最大为32k,完全可以通过33k重叠压缩块。2. “很可能瓶颈在网络上。并行压缩步骤是完全浪费的,实际上只会通过降低压缩比而减慢速度。”-就像可能的一样错误。每当瓶颈是网络时,压缩都会加速事情的进行。 - No-Bugs Hare
  1. “你可能不想使用ZIP格式,因为它是过时的技术,有相当大的缺点,而且显然你有一些非常具体的需求。” - 根据答案和随后的OP评论,这些“特殊需求”需要ZIP格式,简单明了。
  2. “使用另一种算法并配置它以获得更好的压缩率,代价是CPU性能。并行化是无关紧要的;它不是瓶颈,所以根本没有必要这样做。” - 再次错误。只要由于速度较慢,压缩本身不成为瓶颈,这才是正确的。
- No-Bugs Hare
@No-BugsHare,您已经决定对此帖子进行令人憎恨的打击反应。然而,在您的第一条评论中,您完全错过了重点,并以奇怪的方式阅读了这个答案中的一行。我很确定是你的问题,而不是难以理解的问题。如果瓶颈是管道,则__并行压缩__ 步骤没有用。我不是说“如果管道是问题,请勿压缩”。我是说:“如果管道是问题,请不要并行压缩,只需按常规压缩”。 - rzwitserloot
@rzwitserloot,那么您对我提出的其他三个观点没有异议吗?特别是关于压缩与并行化“根本上不相容”的观点——这是_根本上_错误的吗?顺便说一句,您对压缩的定义也是错误的(压缩不一定需要在“字节块”上工作)——而且,在某些情况下(比如“成为更大位流的一部分”),完全有可能压缩一个单独的字节(提示——只有LZ系列寻找重复,熵编码器不会)。 - No-Bugs Hare
@No-BugsHare,我显然发现你只是想通过错误解释管道是瓶颈来获得互联网积分。我猜你想挑起争端,但我对此不感兴趣。 - rzwitserloot

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接