2012-06-28 86 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

最後一段可以解釋你的情況。 –

相關問題