2017-10-18 13 views
0

リモートソケットを継続的に聴いて、指定された入力に対して反応する必要があります。JavaソケットリスナーCPU負荷100%

public void listen(String ip, int port) { 
    try (
     Socket socketListener = new Socket(ip, port); 
     BufferedReader portReader = new BufferedReader(new InputStreamReader(socketListener.getInputStream())); 
    ) { 
     while (true) { 
     while (!portReader.ready()) { 
      // Wait for next PORT message 
     } 

     Logger.log(LogComponent.SOCKET, "Event received"); 
     } 
    } 
    } 

私は上記のコードが100%のCPU負荷を使用しているので非常に間違っていますか?

デバッグ中は、while-!portreader-loopが悪意のある人であることがわかります。しかし、私が見つけた例のほとんどは同じようにそれをやっています。あなたのコメントを考慮し

EDIT#1

私は今のソリューションを次ています

try { 

    Socket SocketListener = new Socket(ip, port); 
    BufferedReader portReader = 
    new BufferedReader(
     new InputStreamReader(SocketListener.getInputStream()) 
    ); 

    // We do not use common while(true)-pattern for reading the input. 
    // Instead, we check for new input 3 times a second. 
    ScheduledExecutorService executor = Executors.newScheduledThreadPool(10); 
    executor.scheduleAtFixedRate(() -> { 
    try { 
     processInput(portReader); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
    }, 0, 333, TimeUnit.MILLISECONDS); 

} catch (Exception exception) { 
    exception.printStackTrace(); 
} 

そしてprocessInput(0)は今、行動を行っています。 これは単純にThread.sleep()を使用するよりもパフォーマンスが向上しますが、理由はわかりません。

このアプローチを使用する場合:コードがソケットからメッセージをいくつか見逃している可能性がありますか?私はその間隔の間に意味する?

+1

「while true」は、CPUが許す限り速く実行されます。したがって、ループを遅くするためには '遅延'が必要です。 1秒あたりの頻度を計算して、リモートソケットをチェックし、適切な遅延を挿入します。たとえば1/10秒待機すると、1秒あたり約10回のチェックが行われます(チェック時間を引いたもの)。 –

+0

また、メッセージの終わりを示すバイトを提供する必要があります。あなたのコードが-1を返すことは決してありません。あなたはストリームを閉じる必要があります。 – MissingSemiColon

+0

ブロッキング読み出しを実行できないのはなぜですか?読みやすさをテストするために 'Reader.ready()'を使うのは間違った設計です。ノンブロッキング動作が必要な場合は、SelectableChannelsやJava 7で導入された非同期入出力機能を使用することを検討してください。 –

答えて

0

問題は、while(true)内のコードがすべてのCPUを消費していることです。

public void listen(String ip, int port) { 
    try (Socket socketListener = new Socket(ip, port); 
    BufferedReader portReader = new BufferedReader(new InputStreamReader(socketListener.getInputStream()));) { 
     while (true) { 
      while (!portReader.ready()) { 
       // Wait for next PORT message 
       try { 
        Thread.sleep(1); 
       } catch(InterruptedException e) { 
        //handle InterruptedException 
       } 
      } 
      Logger.log(LogComponent.SOCKET, "Event received"); 
     } 
    } 
} 
+0

portReader.ready()はサーバーがデータを送信する場合にのみtrueです。 –

0

それはwhileループ内の命令を処理しているためお使いのCPUがビジー状態である:のような単一の変更を行います。

これを避けるには、ソケットが接続されるのを待つ関数を使用する必要があります。着信接続を待っている場合は、Socket.accept()を使用してください。これにより、接続が確立されるまでスレッドがブロックされます(つまり、スレッドは実行のスケジュールが設定されません)。

Thread.sleep()はお勧めしません。これによりCPU使用率はやや低下しますが、CPUを不必要に消費し、遅延を招くことになります。これは悪い工学的実践です。

それ以外にも、非ブロッキングまたは非同期のI/Oを調べることができます。詳細についてはSee hereをご覧ください。

+0

サーバはすぐにソケットを受け入れますが、これは問題ではありません。その後、ソケットは連続して開いたままになります。しかし、それはちょうど2秒ごとにデータを送信しています。リンクありがとう! –

+0

その場合、 'portReader.read()'を試すことができます。あなたのEDIT#1では、別のスレッドでCPUを無駄にしていますが、それはまだあなたが探している解決策ではありません。実際には以前よりも悪化しています。 – jurez

+0

https://docs.oracle.com/javase/tutorial/networking/sockets/clientServer.htmlも参照してください。 – jurez

関連する問題