处理大数据量的建议

7

我有一些“大量”的ASCII格式的数值数据文件(总共占用几个GB),我的程序需要至少一次按顺序处理它们。

有关存储/加载数据的建议吗? 我考虑将文件转换为二进制格式,以使它们更小且加载速度更快。

我应该一次性将所有内容加载到内存中吗?
如果不是,那么部分加载数据的好方法是什么?
有哪些与Java相关的效率技巧?


2
@Jake:我写了一个Java应用程序来处理几千兆字节的文本文件(包括ASCII,UTF-8和UTF-16{be,le})。 最重要的是转换为生产者/消费者模式,并将负载分散到几个核心上(适应机器)。我们有一个线程进行I/O,生成要消耗的“块”。然后我们有几个线程并行处理数据。使用16个内核的CPU监视器可以看到它的惊人表现:)因此,基本上您必须找到何处受限制:您是I/O受限还是CPU受限?如果您是CPU受限,我的建议是并行化。 - SyntaxT3rr0r
11个回答

8
那么,如果处理需要在多个文件和多个缓冲区之间跳转,那该怎么办?不断打开和关闭二进制文件会变得很昂贵吗?
我是“内存映射I/O”(也称为“直接字节缓冲区”)的忠实粉丝。在Java中,它们被称为映射字节缓冲区,是java.nio的一部分。(基本上,这种机制使用操作系统的虚拟内存分页系统将您的文件“映射”并以编程方式呈现为字节缓冲区。操作系统将自动管理将字节从磁盘移动到内存,速度非常快。)
我建议采用这种方法,因为a)它对我有效,b)它将让您专注于算法,并让JVM、操作系统和硬件处理性能优化。他们比我们这些卑微的程序员更了解最佳情况。;)
在您的情况下,如何使用MBBs?只需为每个文件创建一个MBB,并根据需要读取它们。您只需要存储结果。

顺便问一下,你处理的数据量有多大,以GB为单位?如果超过3-4GB,32位机器上的MBB实现将依赖于平台体系结构可寻址内存空间,因此这对你来说行不通。64位机器和操作系统将使您达到1TB或128TB的可映射数据。

如果您考虑性能,那么要知道Kirk Pepperdine(一个有点出名的Java性能专家)。他参与了一个网站www.JavaPerformanceTuning.com,其中包含一些更多的MBB细节:NIO Performance Tips和其他Java性能相关内容。


2
你可能想要查看Wide Finder项目中的条目(在Google上搜索"wide finder" java)。 Wide Finder涉及读取日志文件中的大量行,因此请查看Java实现并查看那些可行和不可行。

1

您可以将数据转换为二进制,但如果需要保留原始数据,则会有1个或多个副本。

建议在原始ASCII数据上构建某种索引,这样如果需要再次处理数据,则可以更快地进行处理。

按顺序回答您的问题:

我应该一次性将所有内容加载到内存中吗?

如果不必要,最好不要这样做。对于某些文件,您可能能够这样做,但如果仅按顺序处理,请逐个缓冲读取,沿途存储所需内容即可。

如果不这样做,部分加载数据的良好方法是什么?

BufferedReader /等最简单,尽管您可以深入研究FileChannel /等,使用内存映射I/O以按窗口方式浏览数据。

有哪些Java相关的效率提示?

这实际上取决于您对数据本身的操作!


1

没有任何关于正在进行的处理类型的额外见解,以下是我在做类似工作时的一些一般想法。

  1. 编写应用程序的原型(甚至可以是“一次性使用”),对数据集执行任意操作。看看它有多快。如果你能想到的最简单、最天真的方法足够快,那就没问题了!

  2. 如果天真的方法不起作用,请考虑预处理数据,以便后续运行在可接受的时间内运行。你提到必须在数据集中“跳来跳去”。有没有办法将其预处理掉?或者,一个预处理步骤可以生成更多的数据 - 索引数据 - 提供关键、必要部分的字节精确位置信息。然后,你的主处理运行可以利用这些信息直接跳转到必要的数据。

因此,总结一下,我的方法是现在尝试一些简单的东西,看看性能如何。也许会很好。否则,研究一下将数据分步处理,将最昂贵的操作保存为不频繁的预处理。

不要“将所有东西加载到内存中”。只需执行文件访问操作,让操作系统的磁盘页面缓存决定何时实际从内存中直接提取内容。

@2: 不,我需要为数据的窗口提供随机访问(同时对所有文件进行操作)。 - Jake

1

这在很大程度上取决于文件中的数据。大型主机已经进行顺序数据处理很长时间了,但它们通常不使用随机访问数据。它们只是一次读取一行并处理相应数量的数据,然后继续。

对于随机访问,通常最好建立具有缓存封装器的对象,这些封装器知道需要构造的数据在文件中的位置。当需要时,它们读取该数据并构造自己。这样,当内存不足时,您可以开始杀掉一些东西,而不必太担心以后无法恢复。


0

你并没有给我们足够的信息来帮助你。你需要一次性加载每个文件以便处理吗?还是可以逐行处理?

一次性加载整个文件很可能会导致性能不佳,即使对于那些不是特别大的文件也是如此。你最好定义一个适合自己的缓冲区大小,并一次读取/处理一定量的数据。


是的,我绝对可以并且应该使用缓冲区。那么如果处理需要在多个文件和多个缓冲区之间跳转呢?反复打开和关闭二进制文件会变得很昂贵吗? - Jake

0

我发现Informatica是一款非常有用的数据处理工具。好消息是,最近的版本甚至允许Java转换。如果你正在处理数千兆字节的数据,那么现在可能是时候投资于最佳ETL工具了。

我假设您想在此处对处理结果进行某些操作,例如将其存储在某个地方。


0
如果您的数值数据是定期采样的,并且需要进行随机访问,请考虑将它们存储在四叉树中。

0
我强烈建议利用正则表达式,并研究“新”的IO nio包,以实现更快的输入。这样,您可以合理地期望处理几千兆字节的数据时速度更快。

0
如果可能的话,将数据存入数据库中。这样你就可以利用所有可用的索引、缓存、内存固定和其他功能。

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