2013-05-08 534 views
1

爲什麼在某些JVM/OS組合上,java.nio.FileChannel的transferTo()和transferFrom()比逐字節傳輸(基於流或使用ByteBuffer)快?爲什麼java.nio.FileChannel的transferTo()和transferFrom()更快?它使用DMA嗎?

這些方法是否使用直接存儲器訪問(DMA)而不是爲每個字節傳輸發出中斷請求(IRQ)?

+0

Both。 IRQ用於磁盤傳輸,然後通過DMA完成。這不是NIO或Java所獨有的:操作系統已經工作了幾十年。不是一個真正的問題。 – EJP 2013-05-09 12:37:16

回答

3

這些方法是否使用直接內存訪問(DMA)而不是爲每個字節傳輸發出中斷請求(IRQ)?

具體細節取決於實際的實現,它們不需要使用任何特定的機制。這是在文檔中暗示爲transferTo(重點煤礦):

此方法是潛在比簡單的循環,從該信道的讀取和寫入到所述目標信道有效得多。 許多操作系統可以直接從文件系統高速緩存傳輸字節到目標通道,而無需實際複製它們。

'潛在','很多'...所以沒有保證。

這有一定道理的假設,這是可能更有效地使用該方法,如果只有輕微的話,因爲你讓JVM到快捷通過本地代碼(如果使用支持的信道類型)。在「簡單的循環」,他們形容的作品有點像如下:,儘管這段代碼使用直接緩衝區

ByteBuffer buf = ByteBuffer.allocateDirect(BUF_SIZE); 
while (/* read more condition */) { 
    source.read(buf); 
    buf.flip(); 
    target.write(buf); 
    buf.compact(); 
} 

注意,你還是回來戳成Java緩衝器管理(閱讀,翻頁,書寫,緊湊)。一個優化編譯器可能能夠省略一些,但它可能不會。

但是,使用transferTo/transferFrom將其留給JVM決定如何傳輸字節。如果平臺對這種傳輸具有本地支持,則可以在不創建中間緩衝區的情況下這樣做。如果沒有這樣的支持,the JVM can still implement a loop such as above

示例:假設SocketChannel被告知直接從FileChannel通過transferFrom讀取數據。 FileChannel最近被讀取,其內容位於OS文件緩存中。 SocketChannel可以直接指向OS文件緩存並從那裏開始傳輸,而不是讀取和複製字節到緩衝區。至少消除了一輪複製。

現在進一步假設套接字(A)實際上連接到某個其他本地進程,例如使用一種稱爲SocketChannel B的管道。當B開始讀取它從A獲得的內容時,它實際上可能是直接讀取從操作系統文件緩存再次。如果B剛剛使用transferTo到另一個頻道...你就明白了。

0

有在FileChannel API一些解釋

This method is potentially much more efficient than a simple loop that reads from the source channel and writes to this channel. Many operating systems can transfer bytes directly from the source channel into the filesystem cache without actually copying them. 

BTW兩者的transferTo()和transferFrom()是抽象的,所以這一切都取決於實際執行

+0

感謝您的貢獻。我知道我的問題值得一個RTFM類型的答案。令我厭惡的是,javadoc非常模糊,所以如果對JVM實現細節有深入的瞭解的人可以在這個問題上提供更多的清晰度,那將是非常棒的。我想DMA和IRQ的問題與硬件一樣多,關於操作系統...... – murungu 2013-05-08 23:15:01

0

它使用DMA /零拷貝,從而節省從「從」緩衝區到CPU的傳輸,然後從CPU到「到」緩衝區的傳輸。對於更詳細的解釋閱讀IBM

this文章
+0

*文中提到的所有*磁盤傳輸都使用DMA,而不僅僅是'transferFrom/To()'。 – EJP 2013-05-09 00:03:41

相關問題