将大量数据从内存写入文件的最快方法是什么?

时间:2012-04-09 16:49:35

标签: java file io

我有一个程序可以生成大量数据并将其放入队列中进行写入但问题是它生成的数据比我当前正在编写的更快(导致它达到最大内存并开始减速)。订单无关紧要,因为我打算稍后解析文件。

我环顾四周,发现了一些帮助我设计当前流程的问题(但我仍觉得它很慢)。到目前为止,这是我的代码:

//...background multi-threaded process keeps building the queue..
FileWriter writer = new FileWriter("foo.txt",true);
        BufferedWriter bufferWritter = new BufferedWriter(writer);
        while(!queue_of_stuff_to_write.isEmpty()) {
            String data = solutions.poll().data;
            bufferWritter.newLine();
            bufferWritter.write(data);
        }
        bufferWritter.close();

我对编程很陌生,所以我可能会评估这个错误(可能是硬件问题,因为我正在使用EC2),但是有一个非常快速地将队列结果转储到文件中,或者如果我的方法没问题可以我以某种方式改进它?由于顺序无关紧要,在多个驱动器上写入多个文件会更有意义吗?线程是否会让它更快?等等。我不确定最好的方法,任何建议都会很棒。我的目标是保存队列的结果(抱歉没有输出到/ dev / null :-)并保持我的应用程序尽可能低的内存消耗(我不是100%肯定但是队列填满了15gig,所以我我假设它将是一个15gig +文件。

Fastest way to write huge data in text file Java(意识到我应该使用缓冲写入器) Concurrent file write in Java on Windows(让我看到也许多线程写入并不是一个好主意)

4 个答案:

答案 0 :(得分:2)

看一下这段代码,我想到的一件事就是字符编码。你正在编写字符串,但最终,它是转到流的字节。一个编写器的字符到字节编码,它在处理写入的同一个线程中进行。这可能意味着有时间花费编码来延迟写入,这可能会降低写入数据的速率。

一个简单的改变是使用byte[]而不是String的队列,在推入队列的线程中进行编码,并使IO代码使用BufferedOutputStream而不是BufferedWriter

如果编码文本平均每个字符占用的字节少于两个字节,这也可以减少内存消耗。对于拉丁文本和UTF-8编码,这通常是正确的。

但是,我怀疑您可能只是生成数据的速度比IO子系统可以处理的速度快。您需要使您的IO子系统更快 - 通过使用更快的(如果您使用的是EC2,可能租用更快的实例,或写入不同的后端 - SQS与EBS与本地磁盘等),或通过组合几个IO子系统以某种方式并行组合在一起。

答案 1 :(得分:1)

是的,在多个驱动器上写入多个文件应该会有所帮助,如果没有其他内容同时写入这些驱动器,性能应该与驱动器数量成线性关系,直到I / O不再是瓶颈。您还可以尝试其他一些优化来进一步提升性能。

如果您生成大文件并且磁盘无法跟上,则可以使用GZIPOutputStream缩小输出 - 这反过来会减少磁盘I / O的数量。对于非随机文本,通常可以预期压缩率至少为2x-10x。

    //...background multi-threaded process keeps building the queue..
    OutputStream out = new FileOutputStream("foo.txt",true);
    OutputStreamWriter writer = new OutputStreamWriter(new GZIPOutputStream(out));
    BufferedWriter bufferWriter = new BufferedWriter(writer);
    while(!queue_of_stuff_to_write.isEmpty()) {
        String data = solutions.poll().data;
        bufferWriter.newLine();
        bufferWriter.write(data);
    }
    bufferWriter.close();

如果要输出常规(即重复)数据,您可能还需要考虑切换到不同的输出格式 - 例如,数据的二进制编码。根据数据的结构,将其存储在数据库中可能更有效。如果您正在输出XML并且真的想要坚持使用XML,那么您应该考虑Binary XML格式,例如EXI或Fast InfoSet。

答案 2 :(得分:0)

我想只要您从计算中生成数据并且不从其他数据源加载数据,写入总是比生成数据慢。

您可以尝试在多个线程中将数据写入多个文件(不是在同一个文件中 - >由于同步问题)(但我想这不会解决您的问题)。

您是否有可能等待应用程序的写入部分完成其操作并继续计算?

另一种方法是: 你清空队列了吗? solutions.poll()会减少您的解决方案队列吗?

答案 3 :(得分:0)

使用多个线程写入不同的文件是个好主意。此外,您应该查看设置BufferedWriters缓冲区大小,您可以从构造函数中执行此操作。尝试使用10 Mb缓冲区进行初始化,看看是否有帮助