2016-07-15 38 views
-1

Ich schreibe eine einfache Server-Client-Anwendung mit Java NIO, die die Reactor Pattern angewendet. zu meinem Verständnis ist die Reactor Klasse verantwortlich zu sammeln Events (wie: OP_ACCEPT, OP_READ, OP_WRITE).Dispatch Event Handler in separaten Threads im Reaktormuster

Der relative EventHandler würde für die spezifische Aufgabe verantwortlich sein, so denke ich, dass Handler asynchron in separaten Threads ausgeführt werden sollten.

hier ist der Code: enter image description here

, wenn ich dies ausführen, zeigt es einige Probleme, die while-Schleife laufen zu halten, und die Selector hält readyOps Satz (1,4,16) zurückzukehren. Ich denke, es ist, weil die AcceptHanndler nicht die OP_ACCEPT in der blockierenden Weise behandelt, so dass der Schlüssel im Iterator entfernt wird, nach einem select(), würde es wieder auftauchen. Also sollte ich den eventHander nicht als ausführbar betrachten?

Das Konzept der edge-triggered und level-triggered Modelle kommt mir in den Sinn ... ist der Grund, weil der Selektor läuft in level-triggered Modell?

+0

Der ganze Sinn von Selektoren ist, dass Sie * keine * separaten Threads verwenden müssen. – EJP

+0

Der Punkt von 'Selector' ist, mehrere Sockets in einem Thread zu verwalten, ich habe kein Thread pro Client verwendet. – JasonHuang

+0

Sie tun viel schlimmer als das. Sie verwenden grundsätzlich einen Thread * pro Selektor-Ereignis *. Sie sollten die Handler im aktuellen Thread ausführen und nur Hilfsthreads für lang andauernde Ereignisse wie Datenbankzugriffe verwenden, * nachdem * Sie das Akzeptieren oder Lesen abgeschlossen haben oder wo auch immer sich das Ereignis im aktuellen Thread befand. Ihr Grundmodell ist kaputt. – EJP

Antwort

1

Ja, der Selector ist pegelgetriggert. Der Standardarbeitsablauf würde in Ihrem Fall folgendermaßen aussehen: Nachdem Sie festgestellt haben, dass der Kanal akzeptabel ist, brechen Sie diesen Schlüssel von Selector ab und geben diesen Schlüssel erst dann an den Ereignishandler-Thread weiter. Der Event-Handler-Thread würde die Annahme übernehmen und 1) den Server-Socket erneut für OP_ACCEPT registrieren; 2) Registrieren Sie den akzeptierten Client-Socket für OP_READ und/oder OP_WRITE abhängig von dem Protokoll, das Sie implementieren möchten. Alternativ können Sie accept im Hauptthread abschließen (aus Leistungsgründen, wenn ein Schwarm von Clients verbunden ist).

Tatsächlich ist das Unterscheiden von Threads nach Operationstyp nicht skalierbar und kann in SMP-Systemen wegen schlechter Datenlokalität eine schlechte Leistung haben. Es ist besser, jeden Client-Socket mit einem einzelnen Thread zu verbinden. Hochleistungs-Java-Server werden normalerweise implementiert, indem ein Thread ausschließlich zum Akzeptieren (nur einzelne ServerSocket ist dort registriert) und N Worker-Threads zum Arbeiten mit Client-Sockets verwendet wird. Faden Annahme arbeitet in einer Schleife:

  1. Blöcke in select(), bis neue Client eintrifft
  2. akzeptieren vervollständigt
  3. wählt wenigsten belasteten Arbeiter-Thread und überträgt das Eigentum an neu angenommenen Client-Socket es

Jeder Worker-Thread hat seinen eigenen Selector und einen Satz von Client-Sockets und ist verantwortlich für das Lesen/Schreiben dieser Sockets.

+0

tks für Ihre Antwort: D. Wenn der Selector "level-triggered" ist, muss ich alle Event-Handler vor dem nächsten 'select()' abschließen. also das that thread model, das ich wähle, wird nie funktionieren ... eigentlich, was ich dachte, ist nicht jedes 'ereignis' mit einem thread zu halten, ich könnte AIO mit jeder lese-/schreiboperation verwenden, so dass es den thread nicht hält, und der 'Selector' würde einen Thread nehmen, also würde er sich auf 'event collect' konzentrieren ... – JasonHuang