Partage
  • Partager sur Facebook
  • Partager sur Twitter

Coût du multithreading

Sujet résolu
    4 juillet 2016 à 13:52:38

    Bonjour,

    je programme actuellement un jeu de cartes "massivement" multijoueur en ligne (MMOTCG) et je m'attaque depuis quelques temps à tout ce qui concerne le réseau. Le jeu est développé en Java et utilise Netty pour toute la partie réseau. Le modèle que j'ai choisi est très simple et très classique : un serveur auquel se connectent des clients, correspondant aux joueurs physiques.

    Ma question concerne la structure du serveur. Netty me permet de gérer simplement et efficacement les connexions des clients. Cependant, le cœur du jeu consiste à associer deux clients entre eux pour les faire participer à un duel. Chaque duel constitue un ensemble de données particulières, modifiées par les actions des joueurs.

    Actuellement, j'attribue à chaque duel un thread lui correspondant. Pendant sa durée de vie, ce thread passe la très grande majorité de son temps à attendre les demandes des joueurs. Je ne me fais pas de souci concernant l'utilisation du processeur pendant le duel, car ces threads sont bien endormis lorsqu'ils n'ont rien à faire. Cependant, je ne suis pas certain des conséquences que ce très grand nombre de threads parallèles peut entraîner.

    Dois-je craindre des problèmes de mémoire ? Est-ce qu'un grand nombre de threads parallèles, même endormis, peut créer d'autres problèmes de performance côté serveur ? Bref, est-ce que ce multithreading coûte suffisamment cher pour que je doive m'en soucier ?

    Je vous remercie par avance pour votre aide, et n'hésitez pas à me suggérer une autre façon de gérer ces duels si vous considérez qu'elle n'est pas optimale ! :p

    • Partager sur Facebook
    • Partager sur Twitter
      5 juillet 2016 à 19:03:24

      Lu'!

      Créer tous ces threads n'a approximativement aucun intérêt et peu à terme conduire à des pertes de performances à cause d'un trop grand nombre de context-switch qui vont finir par réprésenter un coût notable par rapport à tes opérations effectives qui coûtent complètement peanuts.

      Un modèle bien plus simple serait d'avoir un thread pour l'écoute et l'authentification. Et après un ensemble de workers se partageant les coeurs restant et qui se contente de passer sur chaque duel, regardent si un message est arrivé (sockets non bloquants) et effectuent les opérations demandées. Et l'équilibrage de charge se fait en ajoutant chaque nouveau duel sur le worker qui a actuellement la charge la plus faible.

      • Partager sur Facebook
      • Partager sur Twitter

      Posez vos questions ou discutez informatique, sur le Discord NaN | Tuto : Preuve de programmes C

        6 juillet 2016 à 10:57:02

        Salut et merci beaucoup pour ta réponse !

        Mon idée était en fait de minimiser le nombre de context-switch en appelant la méthode wait() sur chaque thread de duel, qui serait à chaque fois réveillé par le thread principal recevant les messages et les redistribuant ensuite. J'étais tout simplement parti du principe qu'un thread qui attend ne prend jamais la main sur le processeur.

        Mais en effet, la méthode que tu proposes a l'air bien plus efficace. Par contre, d'un point de vue purement technique, je ne suis pas certain de savoir comment la mettre en place. Je passe un peu sur du java, je pourrai recréer un sujet dans le forum approprié si nécessaire.

        Actuellement, ma classe Duel implémente l'interface Runnable. Est-ce que cela implique que je restructure cette classe ? Et en ce qui concerne les workers, il faudrait que je les implémente également moi-même ?

        Idéalement, une classe Worker à laquelle je pourrais ajouter des Runnable qui s'exécuteraient en parallèle serait bien pratique. Mais j'ai la très nette impression que ça reviendrait exactement à ce que je comptais faire à l'origine et que ça ne règlerait aucun souci...

        Edit :

        Executors.newCachedThreadPool();

        ça poserait toujours les mêmes problèmes, j'imagine ? ^^

        -
        Edité par Mustiwa 6 juillet 2016 à 11:00:31

        • Partager sur Facebook
        • Partager sur Twitter
          6 juillet 2016 à 11:31:07

          Mustiwa a écrit:

          Actuellement, ma classe Duel implémente l'interface Runnable. (1) Est-ce que cela implique que je restructure cette classe ? (2) Et en ce qui concerne les workers, il faudrait que je les implémente également moi-même ?

          (1) Oui, mais pas beaucoup, puisqu'il te suffit de ne plus être un Runnable.

          (2) Ouais mais encore une fois, ça casse pas des briques (je code jamais en Java, donc c'est plus du pseudo code) :

          class Worker implement Runnable{
            private List<DuelInfo>    to_add;
            private Map<Client, Duel> client_to_duel;
            private List<Client>      clients;
          
            public synchronized void add_duel(DuelInfo di){
              to_add.add(di);
            }
          
            private synchronized DuelInfo next_duel_info(){
              if(to_add.empty()) return null;
              
              DuelInfo di = to_add.get(to_add.size()-1);
              to_add.remove(to_add.size()-1);
              return di;
            }
          
            private void perform_add(){
              DuelInfo di = next_duel_info();
              while(di){
                Client c1 = di.client1();
                Client c2 = di.client2();
                Duel d = new Duel(c1,c2);
                clients.add(c1);
                clients.add(c2);
                client_to_duel.put(c1, d);
                client_to_duel.put(c2, d);
          
                di = next_duel_info();
              }
            }
          
            void run(){
              while(some_condition){
                perform_add();
          
                for(Client c : clients){
                   if(c.ask_something()){
                      DuelAction da = c.request();
                      Duel d = client_to_duel.get(d);
                      d.perform(da);
                   }
                }
              }
            }
          }
          • Partager sur Facebook
          • Partager sur Twitter

          Posez vos questions ou discutez informatique, sur le Discord NaN | Tuto : Preuve de programmes C

            6 juillet 2016 à 11:44:22

            Ah oui, super, merci beaucoup ! :D

            Ce qui fait qu'il ne me reste plus qu'une seule question : en plus des workers, j'ai au moins deux autres threads qui tourneront à côté. Je crée donc autant de workers que de cœurs restants, ou vaut mieux que je dépasse ce nombre ?

            Edit : en fait t'embête pas, je me poserai ces questions plus tard au moment des tests. Puis c'est un sujet qui a déjà du être traité à énormément de reprises. Encore merci ! ^^

            -
            Edité par Mustiwa 6 juillet 2016 à 11:52:33

            • Partager sur Facebook
            • Partager sur Twitter

            Coût du multithreading

            × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
            × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
            • Editeur
            • Markdown