2012-06-28 58 views
2

第一代码段更快:如何可以在文件多次写入比单个一个

// code is a private "global variable" for the class 
// SourceCodeBuilder is a class that uses StringBuilder() 
// basically it is based on String(s), formatted and with many appends depending on the "loc()" calls (see below) 
private SourceCodeBuilder code = new SourceCodeBuilder(); 

[...] 

    // create "file.txt" and call algorithm 
    fileOut = new FileWriter("file.txt"); 

    for (int i=0; i<x; i++) { 
     algorithm(); 
    } 

算法()是这样的方法:

private void algorithm() { 
    for (int i=0; i<y; i++) { 
     code.loc("some text"); 
     code.loc("other text"); 
     ... 
    } 

    // after "building" the code value I wrote it on the file 
    fileOut.write(code.toString()); 
    fileOut.flush(); 
    code.free(); // this call "empties" the code variable (so the next time algorithm() is called it has the code var sets to "" - it frees a lot of memory) 
       // basically it calls "setLength(0)" method of StringBuilder 
} 

当我在大型文本文件中执行所有这些操作需要大约4500ms的执行时间和少于60MB的内存。

然后我试着用这个其他的代码。 第二一段代码:

private SourceCodeBuilder code = new SourceCodeBuilder(); 

[...] 

    // create "file.txt" and call algorithm 
    fileOut = new FileWriter("file.txt"); 

    for (int i=0; i<x; i++) { 
     algorithm(); 
    } 

    fileOut.write(code.toString()); 
    fileOut.flush(); 
    fileOut.close(); 

如果此时算法()是这样的方法:

private void algorithm() { 
    for (int i=0; i<y; i++) { 
     code.loc("some text"); 
     code.loc("other text"); 
     ... 
    } 
} 

它需要更多的内存大于250MB(和它的确定,因为我不调用代码变量的“free()”方法,所以它是一个“连续”附加在同一个变量上),但是令人惊讶的是它需要超过5300ms才能执行。 这比第一个代码慢了大约16%,我无法向自己解释原因。

在第一个代码中,我会在“file.txt”上多次写入多个文本块。在第二个代码中,我写了一大段文字,但只有一次,在“file.txt”上,并使用了更多的内存。随着第二个代码,我期待更多的内存消耗,但没有更多的CPU消耗(仅仅因为有更多的I/O操作)。

结论:即使第一个代码比第二个执行更多的I/O操作,第一个代码也比第二个快。为什么?我错过了什么吗?

+0

你在这里的措辞很混乱;目前还不清楚哪个是哪个,你的基准测试哪个更好,等等。 –

+0

我试图更好地解释自己......你不了解什么? – HBv6

+0

StringBuilder是否必须在每次达到一定长度时重新分配它? –

回答

3

缓慢地填充大内存缓冲区时,所需的时间非线性增长,因为您需要多次重新分配缓冲区,每次将整个内容复制到内存中的新位置。这需要时间,特别是当缓冲区为200MB +时。如果您预先分配缓冲区,您的过程可能会更快。

但是,以上所有仅仅是我的猜测。你应该分析你的应用程序,看看附加时间到底在哪里。

+0

因此在这种情况下,内存(重新)分配过程比多个I/O操作要慢。谢谢 – HBv6

+1

I/O操作也会进行缓冲,然后它们会定期刷新到磁盘,以最大限度地减少实际写入次数。当您多次写入时,您可以让I/O系统决定何时执行真正的I/O操作;当你做一个巨大的写作,你自己决定。 – dasblinkenlight

4

每个系统调用都有一个开销,可以通过使用BufferedWriter或reader或流来避免。 (这就是为什么你会使用缓冲)

在第一种情况下,您在写入之前缓冲整个内容。在第二种情况下,你一次只写一点文件,这会导致更多的系统调用,从而导致更多的开销。

如果您要更快地生成文件,您可能会发现几乎所有的时间都花费在系统调用中。

您以块(使用缓冲)流式传输数据的原因是,您不需要太多的内存。即有更大的缓冲区让你放慢脚步而不是帮助你。

在你的情况,我怀疑你正在写一个StringBuilder或StringWriter(它使用StringBuffer),并且它必须被复制,因为它的大小被调整为最终需要的大小。 这会产生一些GC开销,从而导致更多复制。

+0

对不起,但在第一种情况下,我没有按照你所说的去做。我只在第二种情况下缓冲内容,然后在文件上写入(1次)。这与你所说的完全相反......但我仍然明白你的意思。 – HBv6

+1

最后一段可以解释你的情况。 –

相关问题