2016-07-15 1 views
-1

J'écriture d'une application client-serveur simple avec Java NIO qui a appliqué la Reactor Pattern. à ma compréhension, la classe Reactor est responsable de recueillir Events (comme: OP_ACCEPT, OP_READ, OP_WRITE).gestionnaire d'événements de répartition dans des threads séparés dans le modèle de réacteur

Le relatif EventHandler serait responsable de la tâche spécifique, donc je pense que les gestionnaires devraient fonctionner dans des threads séparés de manière asynchrone.

Voici le code: enter image description here

quand je lance cela, il montre quelques problèmes, la boucle while continuer à courir, et le Selector garde retour readyOps ensemble de (1,4,16). Je suppose que c'est parce que la AcceptHanndler ne pas manipuler la OP_ACCEPT de la manière de blocage, si l'événement est la clé supprimer dans le iterator, après une select(), il montrerait à nouveau. Donc ne devrais-je pas prendre le eventHander en tant que runnable?

Le concept de edge-triggered et level-triggered modèles vient à l'esprit ... ne la raison est parce que le sélecteur est runing dans level-triggered modèle?

+0

Le point entier de Selectors est chapeau que vous * ne * devez utiliser des threads séparés. – EJP

+0

Le point de 'Selector' est de gérer plusieurs socket dans un thread, je n'ai pas utilisé de thread par client. – JasonHuang

+0

Vous faites bien pire que ça. Vous utilisez essentiellement un thread * par événement de sélection *. Vous devez exécuter les gestionnaires dans le thread en cours et utiliser uniquement des threads auxiliaires pour les événements de longue durée tels que les accès à la base de données *, après avoir terminé l'acceptation ou la lecture ou l'événement dans le thread en cours. Votre modèle de base est cassé .. – EJP

Répondre

1

Oui, le sélecteur est déclenché par niveau. Dans votre cas, le flux de travail standard serait le suivant: après avoir détecté que ce canal est acceptable, annulez cette clé à partir de Selector et seulement après cette transmission de cette clé au thread du gestionnaire d'événements. Le thread du gestionnaire d'événements doit accepter et 1) enregistrer à nouveau le socket du serveur pour OP_ACCEPT; 2) enregistrer le socket client accepté pour OP_READ et/ou OP_WRITE en fonction du protocole que vous souhaitez implémenter. Alternativement, vous pouvez compléter accepter dans le thread principal (pour des raisons de performances, s'il y a un essaim de clients se connectant).

En fait, la différenciation des fils par type d'opération n'est pas extensible et peut avoir de mauvaises performances dans les systèmes SMP en raison de la mauvaise localisation des données. Il est préférable de verrouiller chaque socket client sur un thread unique. Les serveurs Java hautes performances sont généralement implémentés en ayant un thread exclusivement pour accepter (seul un seul serveur ServerSocket y est enregistré) et N threads de travail pour travailler avec les sockets client. Accepter fil fonctionne dans une boucle:

  1. blocs select() jusqu'à ce que nouveau client arrive
  2. termine acceptent
  3. choisit thread de travail moins chargé et transfère la propriété de socket client nouvellement accepté il

Chaque thread de travail a son propre sélecteur et un ensemble de sockets client et est responsable de la lecture/écriture de ces sockets.

+0

tks pour votre réponse: D. Si le Selector est 'level-triggered', alors je dois compléter tous les event-handlers avant' select() '. donc ce modèle de thread que je choisis ne fonctionnera jamais ... en fait ce que je pensais ne pas contenir chaque 'événement' avec un thread, je pourrais utiliser AIO avec chaque opération de lecture/écriture, donc il ne tiendra pas le fil, et le 'Selector' prendrait un thread afin qu'il se concentre sur' event collect' ... – JasonHuang