2012-08-17 36 views
2

比方說,我們有SocketChannel(處於非阻塞模式),它已向Selector註冊以獲得讀取興趣。比方說select()之後,Selector告訴我們這個通道已經準備好讀取,並且我們有一些ByteBuffer。我們想從我們的通道讀取一些字節到這個緩衝區(在讀取之前,ByteBuffer被清除)。爲此,我們使用channel的read()方法返回實際讀取的字節數。讓我們假設從通道讀取這個數字是正數,並且ByteBuffer的方法hasRemaining()返回true。在這種情況下立即嘗試從同一頻道讀取更多內容是否實用? write()的問題。如果write()返回正值並且並非緩衝區的所有內容都已發送,那麼在write()返回0之前立即再次嘗試是否可行?使用Java NIO的高效讀/寫方法

+0

只要您處於非阻塞狀態,您應該讀/寫,直到返回值爲<= 0,這意味着它會阻塞或結束流。順便提一下,你的頻道通常會寫入準備好,所以你應該避免使用寫入興趣,因爲它會讓你的'select'循環旋轉。當寫入數據之前'SocketChannel.write'會被阻塞時,纔會對寫入準備狀態感興趣。 – oldrinb 2012-08-17 02:13:28

+0

@veer是的,我忘了提及所有這些都是關於非阻塞模式。 – Rubio 2012-08-17 02:16:26

+0

但是直到返回值<= 0才嘗試真的有效嗎?我的意思是,如果上一次read()返回> 0但未能完全填充緩衝區,是否真的值得嘗試再次讀取?這個下一個read()會返回正值的概率很高嗎?或者正返回值和非完全填充的緩衝區表明我們(很可能)耗盡了內部套接字緩衝區並應該返回到選擇狀態? – Rubio 2012-08-17 02:28:11

回答

0

如果您得到一個短讀取結果,沒有更多的數據要讀取沒有阻塞,所以你不能再讀,直到存在。否則,下一次讀取幾乎肯定會返回零或-1。

如果讀取填充緩衝區,從一個連接的角度來看,它可能是有意義的,直到它返回< = 0,但是您正在從其他通道中竊取週期。你也需要考慮公平。一般來說,你應該做一個閱讀並繼續迭代選定的鍵。如果有更多的數據,那麼選擇下次會告訴你。

使用大緩衝區。

這也意味着在每次讀取之前清除緩衝區是錯誤的。您應該用flip/get/compact循環獲取數據,然後緩衝區已準備好再次讀取,您不會冒失去數據的風險。這反過來意味着您需要每個連接的緩衝區。

+0

感謝您的回答!緩衝區清除僅僅是爲了舉例 - 爲了澄清緩衝區的初始狀態。 – Rubio 2012-08-17 04:37:20

0

這一切都取決於數據到達的數據速率以及應用程序的延遲要求。如果您根本不關心延遲,那麼您可能會延遲讀取興趣,直到您懷疑有足夠的數據到達緩衝區,纔會獲得稍高的帶寬。

雖然你必須小心。延遲讀取可能會迫使內核緩衝更多數據,可能會填充緩衝區,並且必須開始丟棄數據包或以其他方式進行一些流量控制。這不僅會殺死最後一段的任何好處。

因此,一般來說,您希望儘可能早地閱讀。批量讀取的好處很少,最大的潛在缺陷可能很大。請記住,您看到的是非完整讀取的事實意味着您正在處理數據的速度比進入的速度要快。換句話說,您處於有CPU刻錄的狀態,所以額外的較小讀取的開銷基本上是免費的。

+0

我並不完全同意「批量讀取的好處很少」 - 請小心,因爲許多小讀取會給機械驅動器帶來巨大的負擔。當你有多個用戶時,這會放大,因爲驅動器會尋找很多,只能讀取小塊數據。同時請求數量,可用內存和延遲要求之間的平衡。 – Joe 2012-11-05 20:03:47

+0

@Joe:首先,我們談論的是網絡,而不是磁盤。即使它是磁盤,磁盤(和操作系統)也有緩存,所以你實際上不會在每個請求上尋找。 – 2012-11-05 20:11:45