8

我在我的程序中使用了 GZIPInputStream,我知道如果我能让 Java 并行运行我的程序,性能会有所帮助。

一般来说,标准虚拟机是否有一个命令行选项可以在多核上运行?它只在一个上运行。

谢谢!

编辑

我在 Windows XP 上运行普通的 Java SE 6 更新 17。

将 GZIPInputStream 放在单独的线程上会显式帮助吗?不!不要将 GZIPInputStream 放在单独的线程上!不要多线程 I/O!

编辑 2

我想 I/O 是瓶颈,因为我正在读取和写入同一个磁盘......

不过,一般来说,有没有办法让 GZIPInputStream 更快?或者替代并行运行的 GZIPInputStream?

编辑 我使用的 3 代码片段:

GZIPInputStream gzip = new GZIPInputStream(new FileInputStream(INPUT_FILENAME));
DataInputStream in = new DataInputStream(new BufferedInputStream(gzip));
4

9 回答 9

16

AFAIK 从这个流中读取的动作是单线程的,所以如果你正在读取一个文件,多个 CPU 不会帮助你。

但是,您可以有多个线程,每个线程解压缩一个不同的文件。

话虽如此,如今解压缩并不是特别密集的计算,您更有可能因 IO 成本而受阻(例如,如果您在 HD 的两个不同区域读取两个非常大的文件)。

更一般地说(假设这是一个 Java 新手的问题),Java 不会为您并行地做事情。您必须使用线程来告诉它您想要执行哪些工作单元以及如何在它们之间进行同步。Java(在操作系统的帮助下)通常会占用尽可能多的内核,并且如果线程多于内核(通常是这种情况),也会在同一内核上交换线程。

于 2010-01-01T21:14:12.667 回答
6

PIGZ = GZip 的并行实现是 gzip 的全功能替代品,它在压缩数据时充分利用了多个处理器和多个内核。http://www.zlib.net/pigz/ 它还不是 Java --- 任何接受者。当然,世界需要 Java。

有时压缩或解压缩会消耗大量 CPU,尽管它有助于 I/O 不会成为瓶颈。

另请参阅 HP 实验室的数据系列 (C++)。PIGZ 仅将压缩并行化,而 Dataseries 将输出分解为可并行解压缩的大压缩块。还具有许多其他功能。

于 2010-01-20T22:15:11.573 回答
2

将您的 GZIP 流包装在缓冲流中,这应该会给您带来显着的性能提升。

OutputStream out = new BufferedOutputStream(
    new GZIPOutputStream(
        new FileOutputStream(myFile)
    )
)

对于输入流也是如此。使用缓冲的输入/输出流可以减少磁盘读取次数。

于 2010-01-01T21:33:42.467 回答
2

我没有看到任何解决程序其他处理的答案。

如果您只是解压缩文件,最好使用命令行gunzip工具;但是您从该流中提取的文件可能会发生一些处理。

如果您要提取大小合理的块的内容,那么您对这些块的处理应该在与解压缩不同的线程中进行。

您可以在每个大字符串或其他数据块上手动启动一个线程;但是从 Java 1.6 左右开始,您最好使用 中的一个花哨的新类java.util.concurrent,例如ThreadPoolExecutor.


更新

从问题和其他评论中我不清楚您是否真的只是在使用 Java 提取文件。如果你真的,真的认为你应该尝试与 竞争gunzip,那么你可能会通过使用大缓冲区来获得一些性能;即使用 10 MB 的缓冲区(二进制,而不是十进制!- 1048576),将其填充到单个 gulp 中并同样将其写入磁盘。这将使您的操作系统有机会对磁盘空间进行一些中等规模的规划,并且您也需要更少的系统级调用。

于 2010-01-01T21:45:41.773 回答
0

压缩似乎是并行化的一个难题,因为压缩器发出的字节是前 W 字节输入的重要函数,其中 W 是窗口大小。显然,您可以将文件拆分为多个片段,并为在各自线程中运行的每个片段创建独立的压缩流。您可能需要保留一些压缩元数据,以便解压缩器知道如何将文件重新组合在一起。

于 2010-01-01T21:34:23.763 回答
0

使用 gzip 压缩和解压是一个序列化的过程。要使用多个线程,您必须制作一个自定义程序来将输入文件分解为多个流,然后使用一个自定义程序来解压缩并将它们重新组合在一起。无论哪种方式,IO 都将成为 CPU 使用率之前的瓶颈。

于 2010-01-01T21:49:42.763 回答
0

运行多个虚拟机。每个 VM 都是一个进程,您应该能够在每个内核上运行至少三个进程,而不会出现任何性能下降。当然,您的应用程序必须能够利用多处理才能受益。没有灵丹妙药,这就是为什么您会在媒体上看到文章抱怨我们还不知道如何使用多核机器。

然而,有很多人将他们的应用程序构建成一个主进程,该主进程管理一个工作进程池并将工作包打包给他们。并非所有问题都可以通过这种方式解决。

于 2010-01-01T22:42:36.277 回答
0

我认为假设多线程 IO总是邪恶的是错误的。您可能需要确定您的特定案例,因为:

  • 最近的操作系统将当前可用内存用于缓存,当您读取文件时,您的文件实际上可能不在硬盘上。
  • 最近的硬盘驱动器(如 SSD)具有更快的访问时间,因此更改读取位置的问题要小得多。
  • 这个问题太笼统了,无法假设我们正在从单个硬盘驱动器读取。

您可能需要调整读取缓冲区,使其足够大以降低切换成本。在边界情况下,可以将所有文件读入内存并在其中并行解压缩 - 速度更快,并且在 IO 多线程上没有任何损失。然而,不那么极端的东西也可能效果更好。

您也无需执行任何特殊操作即可在 JRE 上使用多个可用内核。不同的线程通常会使用由操作系统管理的不同内核。

于 2013-02-09T10:37:45.950 回答
0

您不能并行化标准GZipInputStream,它是单线程的,但是您可以将解压流的解压和处理流水线化到不同的线程中,即将 GZipInputStream 设置为生产者,将其处理为消费者,并将它们与有界阻塞队列。

于 2018-07-10T10:35:47.453 回答