簡體   English   中英

SocketChannel.write()的Java NIO線程問題

[英]Java NIO Threading issue with SocketChannel.write()

有時,在通過SocketChannel.write()發送大量數據時,底層TCP緩沖區會被填滿,我必須不斷重新嘗試write(),直到數據全部發送完畢。

所以,我可能有這樣的事情:

public void send(ByteBuffer bb, SocketChannel sc){
   sc.write(bb);
   while (bb.remaining()>0){
      Thread.sleep(10);
      sc.write(bb);          
   }
}

問題是大型ByteBuffer和溢出的底層TCP緩沖區的偶然問題意味着對send()的這個調用將阻塞意外的時間。 在我的項目中,有數百個客戶端同時連接,一個套接字連接引起的一個延遲可以使整個系統爬行,直到解決了一個SocketChannel的延遲。 當發生延遲時,它可能導致項目其他區域的連鎖反應減慢,並且具有低延遲很重要。

我需要一個解決方案,它將透明地處理這個TCP緩沖區溢出問題,並且在需要多次調用SocketChannel.write()時不會導致阻塞所有內容。 我已經考慮將send()放入一個擴展Thread的單獨類中,因此它作為自己的線程運行,並且不會阻塞調用代碼。 但是,我擔心為我正在維護的EACH套接字連接創建一個線程所需的開銷,特別是當99%的時候,SocketChannel.write()在第一次嘗試時成功,這意味着線程不需要在那里。 (換句話說,只有在使用while()循環時才需要將send()放在一個單獨的線程中 - 僅在存在緩沖區問題的情況下,可能是1%的時間)如果存在緩沖區問題只有1%的時間,我不需要一個線程的開銷用於其他99%的send()調用。

我希望這是有道理的......我真的可以使用一些建議。 謝謝!

在Java NIO之前,您必須為每個插槽使用一個Thread才能獲得良好的性能。 這是所有基於套接字的應用程序的問題,而不僅僅是Java。 為了克服這個問題,為所有操作系統添加了對非阻塞IO的支持。 Java NIO實現基於Selectors

請參閱最新的Java NIO書籍以及這篇On Java文章,開始使用。 但請注意,這是一個復雜的主題,它仍然會在代碼中引入一些多線程問題。 谷歌“非阻止NIO”獲取更多信息。

你不需要sleep(),因為write會立即返回或阻塞。 如果第一次沒有寫入,你可以有一個傳遞寫入的執行程序。 另一種選擇是使用一小段線程來執行寫操作。

但是,最好的選擇可能是使用選擇器(如建議的那樣),因此您知道套接字何時准備執行另一次寫入。

對於數百個連接,您可能不需要打擾NIO。 良好的老式阻塞插座和線程將為您服務。

使用NIO,您可以在選擇鍵的OP_WRITE注冊興趣,當有空間寫入更多數據時,您將收到通知。

假設您已經使用Selector.select()進行循環,那么您需要做一些事情; 確定哪些插槽已准備好進行I / O.

  • 在創建套接字通道后將其設置為非阻塞,sc.configureBlocking(false);
  • 寫入(可能是部分)緩沖區並檢查是否還有其他內容。 緩沖區本身負責當前位置以及剩余多少。

就像是

sc.write(bb);
if(sc.remaining() == 0)
   //we're done with this buffer, remove it from the select set if there's nothing else to send.
else
    //do other stuff/return to select loop
  • 擺脫睡覺的while循環

我現在面臨一些相同的問題:
- 如果你有少量的連接,但有大量的傳輸,我只會創建一個線程池,並讓寫入阻止寫入線程。
- 如果你有很多連接,那么你可以使用完整的Java NIO,並在你的accept()ed套接字上注冊OP_WRITE,然后等待選擇器進入。

Orielly Java NIO的書就是這一切。
另外: http//www.exampledepot.com/egs/java.nio/NbServer.html? l = lrel

網上的一些研究讓我相信NIO相當過分,除非你有很多傳入的連接。 否則,如果只是幾個大轉移 - 那么只需使用寫線程。 它可能會有更快的反應。 許多人對NIO的問題並沒有像他們想要的那樣快速地進行復制。 由於你的寫線程是自己阻止它不會傷害你。

我讀的關於Java NIO的越多,它就越能給我帶來麻煩。 無論如何,我認為這篇文章解答了你的問題......

http://weblogs.java.net/blog/2006/05/30/tricks-and-tips-nio-part-i-why-you-must-handle-opwrite

聽起來這個家伙比睡眠循環有更優雅的解決方案。

此外,我很快得出結論,單獨使用Java NIO太危險了。 在我可以的地方,我想我可能會使用Apache MINA,它提供了一個比Java NIO更好的抽象和它的“驚喜”。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM