Java - 并行压缩 Gzip

5

我被分配负责在Java 7中并行化GZip,但我不确定哪种方法是可行的。

任务如下:

  • 使用给定数量的线程并行化gzip
  • 每个线程取一个1024 KiB块,使用上一个块的最后32 KiB块作为字典。有一个选项可以不使用字典
  • 从Stdin读取并输出到stdout

我的尝试:

  • 我尝试使用GZIPOutputStream,但似乎没有办法隔离和并行化deflate()操作,也无法访问deflater以更改字典。我尝试继承GZIPOutputStream,但它似乎不像我想要的那样运作,因为我仍然无法隔离压缩/deflate操作。
  • 我尝试使用启用wrap的Deflater和FilterOutputStream输出压缩字节,但我无法正确地将其压缩为GZip格式。我使每个线程都有一个压缩器,它将写入一个字节数组,然后再将其写入OutputStream。

我不确定我的方法是错误的还是完全错了。有人能指出我应该为这个项目使用哪些类吗?


1
这是作业吗?它肯定看起来像是要你从头开始实现,而不是复制GZIPOutputStream。因为你说那个类已经没有并行化了。 - Sean Owen
GzipOutputStream是Deflater的包装器,对吧? - Donal Fellows
是的,这是一个作业任务。我被告知Deflaters应该可以工作,但我似乎无法使它们按GZip格式正确压缩。 - am3692
3个回答

4

是的,使用字典压缩文件不能并行处理,因为所有内容都相互依赖。也许你的老师要求你将多个文件夹中的单个gzip文件并行处理?这将是并行化工作的绝佳示例。


我们应该按顺序读取块,使用先前读取的块中最后32 KiB设置每个块的字典,然后并发压缩。 - am3692
据我所知,并行压缩是一个重要的问题,并且并没有被广泛使用。我非常确定gzip不允许并行化,但是还有其他支持并行化的压缩格式:http://en.wikipedia.org/wiki/Bzip2(尽管这个实现从未被纳入主项目,所以我不会把钱放在上面)。 - Shivan Dragon

2

认为你可以通过在压缩流中插入适当的重置来实现。这个想法是,gzip中使用的底层压缩引擎允许deflater被重置,目的是使其更容易从流损坏中恢复,但代价是使压缩比变差。重置后,deflater将处于已知状态,因此您实际上可以从该状态开始(与正在压缩的内容无关),在多个线程中(当然可以从输入数据的许多位置)生成一个压缩块,并在执行以下重置时包括产生的数据,以便将deflater带回到已知状态。然后,您只需将压缩片段重新组合成整体压缩流即可。“简单!”(哈!)

我不知道这是否有效,我怀疑整个过程的复杂性会使它在除了压缩单个非常大的文件之外不是可行的选择。(如果您有许多文件,最好还是并行压缩每个文件。)尽管如此,这仍然是我首选的方法。

(还要注意,gzip格式只是带有额外元数据的压缩流。)

我也不确定你是否可以使用Java接口来操作zlib引擎。可能它没有暴露足够的接口。而且创建可恢复流的文档也有些模糊不清,这并没有帮助到我们。 - Donal Fellows

1
为了使一个进程并发,你需要有可以同时独立运行的代码部分。大多数压缩算法都是设计成顺序运行的,每个字节都依赖于它之前的所有字节。
唯一实现并发压缩的方法是改变算法(这将与现有方法不兼容)。

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