2017-10-18 5 views
0

Je dois écouter en continu une prise distante et réagir sur une entrée donnée. Qu'est-ce que je fais si mal que le code ci-dessus utilise 100% de la charge de l'unité centrale?Écouteur Java socket Charge CPU de 100%

Lors du débogage, je peux voir que la boucle while-! Portreader-loop est le malfaiteur. Mais la plupart des exemples que j'ai trouvés le font de la même manière.

EDIT # 1

Compte tenu de vos commentaires que j'ai la solution suivante en ce moment:

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(); 
} 

Et processInput(0) fait l'action maintenant. Cela se termine par de meilleurs résultats que l'utilisation de Thread.sleep() - même si je ne comprends pas pourquoi. Lors de l'utilisation de cette approche: Le code peut-il manquer certains messages du socket? Je veux dire pendant les intervalles?

+1

'true' sera toujours aussi rapide que votre processeur le permet. Ainsi, un délai est nécessaire pour ralentir votre boucle. Calculez combien de fois par seconde vous voulez vérifier la prise à distance et insérer un délai approprié. Par exemple, attendre 1/10 de seconde entraînerait environ 10 contrôles par seconde (moins le temps de contrôle). –

+0

Vous devez également fournir un octet qui marque la fin d'un message. La façon dont votre code est conçu ne renverra jamais -1, vous devrez fermer le flux pour que cela se produise. – MissingSemiColon

+0

Pourquoi ne pouvez-vous pas effectuer une lecture bloquante? L'utilisation de 'Reader.ready()' pour tester la lisibilité est une mauvaise conception. Si vous avez besoin d'un comportement non bloquant, utilisez SelectableChannels ou les fonctions d'E/S asynchrones introduites dans Java 7. –

Répondre

0

Le problème est que votre code à l'intérieur de votre while (vrai) consomme tout le CPU. Faire un seul changement comme:

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

Puisque portReader.ready() n'est vrai que si le serveur envoie des données, la consommation du processeur est la même lorsque indle. –

0

Votre CPU est occupé, car il est des instructions de traitement dans la boucle while. Pour l'éviter, vous devez utiliser une fonction qui attend que la prise soit connectée. Si vous attendez une connexion entrante, utilisez Socket.accept(). Cela bloquera le thread (c'est-à-dire que le thread ne sera pas programmé pour l'exécution) jusqu'à ce que la connexion soit établie. Ne pas utiliser Thread.sleep() comme d'autres l'ont suggéré.

Bien que cela réduise quelque peu l'utilisation du processeur, il continuera à brûler le processeur inutilement et à introduire une latence. C'est une mauvaise pratique d'ingénierie. En outre, vous pouvez vous intéresser aux E/S non bloquantes ou asynchrones. See here pour plus d'informations.

+0

Le serveur accepte presque immédiatement le socket, ce n'est pas le problème. La prise reste alors ouverte en permanence. Mais il envoie des données toutes les quelques secondes. Merci pour le lien! –

+0

Dans ce cas, vous pouvez essayer 'portReader.read()' qui devrait bloquer (release thread) jusqu'à ce que l'entrée soit disponible. En ce qui concerne votre EDIT # 1, vous avez maintenant perdu du CPU sur un autre thread, ce n'est toujours pas la solution que vous cherchez, c'est en fait encore pire qu'avant. – jurez

+0

Voir aussi https://docs.oracle.com/javase/tutorial/networking/sockets/clientServer.html – jurez