2013-03-15 56 views
6

我試圖從一個java程序創建300M文件,我從舊的文件API切換到新的java 7 nio包,但是新的包會去甚至比舊的還要慢。Java 7的nio.file包在創建新文件時速度很慢

我看到的CPU利用率比我在使用舊的文件API時少,但是我正在運行這個簡單的代碼,並且我獲得了0.5Mbytes/sec的文件傳輸速率,而且來自java的寫入正在讀取一個磁盤並寫入另一個(寫入是訪問磁盤的唯一進程)。

Files.write(FileSystems.getDefault().getPath(filePath), fiveToTenKBytes, StandardOpenOption.CREATE); 

有沒有希望在這裏獲得合理的吞吐量?


更新:

我拆包從大文件中3億5-10K字節的圖像文件。我有3個磁盤,1個本地和2個SAN連接(大文件上的典型吞吐速率約爲20MB /秒)。

我也試過這個代碼,它將速度提高到幾乎不到2MB/sec的吞吐量(解壓這些文件需要9天的時間)。

ByteBuffer byteBuffer = ByteBuffer.wrap(imageBinary, 0, (BytesWritable)value).getLength()); 
FileOutputStream fos = new FileOutputStream(imageFile); 
fos.getChannel().write(byteBuffer); 
fos.close(); 

我從本地磁盤讀取並寫入SAN連接的磁盤。我從Hadoop SequenceFile格式讀取數據,hadoop通常可以使用基本相同的代碼以20MB /秒的速度讀取這些文件。

唯一不合適的地方,除了超級慢,我看到更多的讀取IO,而不是寫入IO大約2:1,儘管序列文件是gziped(圖像實際上是1:1的比例雖然),所以壓縮文件應該是大約。 1:1與輸出。


月2日更新

看着iostat我看到一些奇數,我們正在尋找xvdf在這裏,我有一個java程序從xvdb讀取和寫入xvdf並沒有ohter流程活躍xvdf

iostat -d 30 
Device:   tps kB_read/s kB_wrtn/s kB_read kB_wrtn 
xvdap1   1.37   5.60   4.13  168  124 
xvdb    14.80  620.00   0.00  18600   0 
xvdap3   0.00   0.00   0.00   0   0 
xvdf   668.50  2638.40  282.27  79152  8468 
xvdg   1052.70  3751.87  2315.47  112556  69464 

的讀取xvdf是10X的寫入,這是令人難以置信的。

fstab 
/dev/xvdf  /mnt/ebs1  auto defaults,noatime,nodiratime  0  0 
/dev/xvdg  /mnt/ebs2  auto defaults,noatime,nodiratime  0  0 
+0

這些文件有多大? – parsifal 2013-03-15 14:07:57

+0

@parsifal「我想創建300M文件[0123]」 – Puce 2013-03-15 14:14:48

+2

我讀爲「我試圖創建300萬(或千)文件」,而不是「我試圖創建一個文件,這是300 Mb的大小「(否則,爲什麼使用」M「而不是」Mb「?)。 – parsifal 2013-03-15 14:15:43

回答

1

我認爲你的緩慢來自創建新文件,而不是實際的轉移。我相信在Linux中創建一個文件是一個同步操作:系統調用將不會返回,直到文件被創建並且目錄被更新。這表明你可以做幾件事:

  • 使用多個寫入器線程和一個讀取器線程。讀取器線程將從源文件讀取數據到byte[],然後創建一個Runnable,從該數組寫入輸出文件。使用有很多線程的threadpool - 可能是100或更多 - 因爲他們將花費大部分時間等待creat完成。根據您擁有的內存量設置此池入站隊列的容量:如果您的文件大小爲10k,那麼隊列容量爲1,000似乎是合理的(沒有理由讓讀者在作者之前過分靠前,所以你甚至可以使用線程數的兩倍)。
  • 而不是NIO,請使用基本的BufferedInputStream s和BufferedOutputStreams。這裏的問題是系統調用,而不是內存速度(NIO類旨在防止堆和堆內存之間的副本)。

我打算假設您已經知道不要試圖將所有文件存儲到一個目錄中。甚至可以在一個目錄中存儲超過幾百個文件。

而作爲另一種選擇,您是否考慮過S3進行存儲?我猜測它的存儲鍵比實際的目錄效率高得多,並且有一個filesystem,它允許你像存儲文件一樣訪問存儲桶(我自己還沒有嘗試過)。

+0

我確實創建了2個進程,並且磁盤速度急劇下降,但2個進程的聚合速度爲2MB /秒,稍微好一點,但看起來並不像更多的異步進程有助於這種情況。至於S3,這是我的第一個想法,它發生了巨大的爆炸。他們的技術人員在線上2周試圖獲得300M文件上傳失敗,並且花費我10k的使用費,即使它第一次工作(它肯定不會),你只是爲了上傳文件而說3k。觀看那些價值$ 0.10/100的小費,它會讓你快速上升! – 2013-03-17 03:13:49

+0

我現在正在嘗試大文件(我可以快速創建),並在大文件中存儲指向字節的指針。到目前爲止,這一切都變得更加順利,而且這是我在閱讀時使用的方法。當我完成時,我會發布它的成功。 – 2013-03-17 03:15:02

+0

最終結果:不要做300M小文件。我們正在轉向一個更復雜的系統,在該系統中,我們將二進制數據加載到大文件中,並保持二進制數據的索引偏移量。我們也在嘗試使用大型的mysql/myisam表作爲一個不錯的選擇。 – 2013-03-17 13:17:34

2

如果我理解正確的代碼,你分割/寫在一小塊一小塊的300M的文件(「fiveToTenKBytes」)。可以考慮使用a Stream approach

如果您正在寫入磁盤,請考慮使用BufferedOutputStream封裝OutputStream。

E.g.像這樣:

try (BufferedOutputStream bos = new BufferedOutputStream(Files.newOutputStream(Paths.getPath(filePathString), StandardOpenOption.CREATE))){ 

... 

} 
+0

@JoachimSauer感謝編輯,但StackOverflow與方法鏈接有問題... – Puce 2013-03-15 14:13:03

+0

我知道,但我添加的鏈接工作正常(至少對我而言)。而現在的那個只會帶你進入'Files'文檔,因爲它有空間。 – 2013-03-15 14:14:49

+0

啊,它似乎是在IE 8中的一個問題。在Firefox它的作品。 – Puce 2013-03-15 14:17:27