IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Entrée/Sortie Java Discussion :

Problème de perf (NIO SocketServerChannel)


Sujet :

Entrée/Sortie Java

  1. #1
    Membre régulier
    Profil pro
    Inscrit en
    Juillet 2004
    Messages
    106
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2004
    Messages : 106
    Points : 78
    Points
    78
    Par défaut Problème de perf (NIO SocketServerChannel)
    Bonjour,

    J'ai un petit problème de performance youhou !

    J'ai essentiellement changé les lignes suivantes:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    Selector selecteur = Selector.open();
    // on enregistre notre serveur auprès du selecteur qu'on vient de créer (en mode accept)
    ssc.register(selecteur, SelectionKey.OP_ACCEPT);
    et

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    SocketChannel client = ssc.accept();
    // on le configure en mode non bloquant pour pouvoir l'enregistrer avec le selecteur
    client.configureBlocking(false);
    SelectionKey clientKey = client.register(selecteur, SelectionKey.OP_CONNECT | SelectionKey.OP_READ | SelectionKey.OP_WRITE, player);
    Edit:
    Une fois la connection établit entre le client et le serveur, les deux saturent les machines, CPU à 100%.

    Mauvaise gestion des selectors? manipulation des clefs? Est-il nécassaire d'utuliser des wakeup? (je n'en utilise pas...)




    Merci.

  2. #2
    Membre régulier
    Profil pro
    Inscrit en
    Juillet 2004
    Messages
    106
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2004
    Messages : 106
    Points : 78
    Points
    78
    Par défaut
    Je réponds à ma question:

    Après 4h de linchage de mon code, j'ai réussi à identifier une partie du problème, et c'est vraiment bête.

    SelectionKey clientKey = client.register(selecteur, SelectionKey.OP_CONNECT | SelectionKey.OP_READ | SelectionKey.OP_WRITE, player);

    A remplacer par

    SelectionKey clientKey = client.register(SelectionKey.OP_READ, player);

    Je passe de 100% de CPU à 4% de CPU (bref, un ordi en idle) avec 20 connexions.

    Donc pour ceux qui ont le même problème de charge processeur sur JAVA NIO sur les selector, bien choisir les opérations lorsqu'on fait le "register".

    Voili voilou.

    fantomasmusic

  3. #3
    Membre éclairé
    Avatar de divxdede
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    525
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Avril 2004
    Messages : 525
    Points : 844
    Points
    844
    Par défaut
    Citation Envoyé par fantomasmusic Voir le message
    Je réponds à ma question:

    Après 4h de linchage de mon code, j'ai réussi à identifier une partie du problème, et c'est vraiment bête.

    SelectionKey clientKey = client.register(selecteur, SelectionKey.OP_CONNECT | SelectionKey.OP_READ | SelectionKey.OP_WRITE, player);

    A remplacer par

    SelectionKey clientKey = client.register(SelectionKey.OP_READ, player);

    Je passe de 100% de CPU à 4% de CPU (bref, un ordi en idle) avec 20 connexions.

    Donc pour ceux qui ont le même problème de charge processeur sur JAVA NIO sur les selector, bien choisir les opérations lorsqu'on fait le "register".

    Voili voilou.

    fantomasmusic
    Effectivement, en régle générale on ne s'enregistre que sur le OP_READ (et accéssoirement sur l'OP_ACCEPT si on est en mode serveur).

    On s'enregistre sur l'OP_WRITE lorsqu'on sait qu'on à quelque chose à écrire sur un canal.
    Cela permet de mettre en "queue" la demande d'écriture et d'être prévenu de façon asynchrone par le selector quand le canal est prêt pour éméttre des données. Une fois les données émises, tu enlèves l'interret pour l'OP_WRITE.

    Si tu t'enregistres sur l'OP_WRITE sans raison alors le selector va sans arret te notifier que tes canaux peuvent êmettre des données (donc ton thread qui gére le selector va tout le temps être reveillé)
    JBusyComponent, une API pour rendre occupé un composant swing.
    SCJP Java 6.0 (90% pass score)

  4. #4
    Membre régulier
    Profil pro
    Inscrit en
    Juillet 2004
    Messages
    106
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2004
    Messages : 106
    Points : 78
    Points
    78
    Par défaut
    En fait, mon serveur écrit quand même, mais j'ai pas besoin de OP_WRITE.
    Mais je ne sais pas si ca correspond à ce que vous disiez précédemment. J'ai émis ce que je pense ci-dessous (après le code).


    Dans mon serveur, j'ai classiquement:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    while (it.hasNext()) {
    // on récupère la clé en cours
    k = (SelectionKey) it.next();
    // on supprime la clé courante de la liste une fois qu'elle a été traité
    it.remove();
     
    // désormais, on teste la nature de l'opération a effectuer
    // si la clé est prête pour un OP_ACCEPT (on accèpte une demanche de connexion sur le serverSocketChannel)
    if(k.isAcceptable()){
     
    SelectionKey clientKey = client.register(selecteur, SelectionKey.OP_READ, player);
     
    // on envoie une requete sur le socketChannel de celui qui vient de se connecter au serveur					
    myHandler.addRequestInQueue(new Request(clientKey, ("00|Who are u?#").getBytes() )); // ajoute la requête à traiter
    (ps: myHandler est un thread qui se charge de traiter la requete)

    ici, le thread qui traite les requêtes (dans une queue)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    // on ititialise les valeurs
    SelectionKey k = request.getSelectionKey();
    byte[] data = request.getData();
     
    SocketChannel client = (SocketChannel) k.channel();
     
    blabla...
    on fait un


    Si j'ai bien compris, là j'utilise l'écriture dans le channel mais pas du tout de manière asynchrone. C'est ça?


    Merci divxdede pour ton explication.

  5. #5
    Membre éclairé
    Avatar de divxdede
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    525
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Avril 2004
    Messages : 525
    Points : 844
    Points
    844
    Par défaut
    Ton écriture est faite de maniere asynchrone vis a vis de l'appelant puisque tu delegues l'écriture dans un thread.

    Mais elle n'est pas asynchrone vis à vis de nio.

    Théoriquement lors de ton addRequestInQueue(...) tu pourrait t'enregistrer sur le OP_WRITE, attendre d'être notifié et ensuite lancer l'écriture effective (dans un thread dédié ou non)

    Mais tout ceci n'est pas aisé, tu as ensuite des problèmes de synchronisation a résoudre, etc...

    Si ca t'interresse, je peu te donner un lien vers du code source correpondant a tout ceci.
    JBusyComponent, une API pour rendre occupé un composant swing.
    SCJP Java 6.0 (90% pass score)

  6. #6
    Membre régulier
    Profil pro
    Inscrit en
    Juillet 2004
    Messages
    106
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2004
    Messages : 106
    Points : 78
    Points
    78
    Par défaut
    Je veux bien oui, si ça te dérange pas, que je puisse jeter un oeil à ça.
    Autre question, enfin plutot ton avis sur la question. Actuellement, mon code est mal codé? mal fichu? on peut mieux faire? ou est-il quand même viable malgré tout?

    Merci.

    Fantomasmusic

  7. #7
    Membre éclairé
    Avatar de divxdede
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    525
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Avril 2004
    Messages : 525
    Points : 844
    Points
    844
    Par défaut
    Citation Envoyé par fantomasmusic Voir le message
    Je veux bien oui, si ça te dérange pas, que je puisse jeter un oeil à ça.
    Autre question, enfin plutot ton avis sur la question. Actuellement, mon code est mal codé? mal fichu? on peut mieux faire? ou est-il quand même viable malgré tout?

    Merci.

    Fantomasmusic
    Tu peu aller sur http://code.google.com/p/objectserver/ ou je suis en train de développer une API pour communiquer par réseau des objets java (basé sur nio)

    Tu peu soit récuperer les sources par svn, soit les parcourir en ligne à cette adresse http://objectserver.googlecode.com/svn/trunk/

    Il y a également une javadoc, la classe responsable de la boucle principale sur le Selector est EventDispachThread

    Il est difficile de critiquer ton code, vu que je n'ai que l'apercu de ta boucle principale sur ton Selector.
    A première vue, le squelette de ton thread principal est sur la bonne voie, cependant il reste pas mal d'embuches sur ton chemin.

    Je te conseillerais de lire les Tricks & Tips de Jean-François Arcand sur nio.

    Le 1er est ici Tricks and Tips with NIO part I: Why you must handle OP_WRITE et il y en a pas mal d'autres qui couvre bien certaines difficultés.

    PS: Je n'ai pas encore officiellement publié cette librairie car j'ai encore de la documentation à écrire et des tests unitaires et de performance à faire. Mais dans l'ensemble elle est terminée. J'en reparlerai probablement d'ici une 15aines de jours sur "developpez" quand tout sera prêt.

    Séb.
    JBusyComponent, une API pour rendre occupé un composant swing.
    SCJP Java 6.0 (90% pass score)

  8. #8
    Membre régulier
    Profil pro
    Inscrit en
    Juillet 2004
    Messages
    106
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2004
    Messages : 106
    Points : 78
    Points
    78
    Par défaut
    Très impressionnant ton projet. Encore plus quand on voit le code.
    PS: je connaissais pas code.google.com ;p il a l'air très bien.

    Merci pour tes liens, je vais aller potasser ça tranquillement, étape par étape sur support papier pour bien comprendre.

    Bonne soirée et bonne continuation dans ton projet.

    Cordialement, Romain.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Problème de perf sous Tomcat 5.5
    Par gamodio dans le forum Tomcat et TomEE
    Réponses: 14
    Dernier message: 18/07/2006, 11h48
  2. [VBA-E] Problème de perf'
    Par MatMeuh dans le forum Macros et VBA Excel
    Réponses: 3
    Dernier message: 05/07/2006, 16h22
  3. Réponses: 11
    Dernier message: 19/06/2006, 16h54
  4. problèmes de perfs IE6/Firefox
    Par fredoche dans le forum Général JavaScript
    Réponses: 0
    Dernier message: 26/08/2005, 17h44
  5. Problème de perfs Sous requetes IN
    Par ias83 dans le forum SQL
    Réponses: 4
    Dernier message: 15/06/2005, 12h39

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo