Ich erinnere mich noch vor zwei oder drei Jahren an ein paar Artikeln, in denen Leute behaupteten, dass moderne Threading-Bibliotheken so gut werden, dass Thread-pro-Anfrage-Server nicht nur einfacher zu schreiben wären als nicht-blockierende Server, sondern auch schneller auch. Ich glaube, dass dies sogar in Java mit einer JVM demonstriert wurde, die Java-Threads Pthreads zuordnete (d. H. Der Java-nio-Overhead war mehr als der Kontext-Switching-Overhead).
Aber jetzt sehe ich, dass alle "hochmodernen" Server asynchrone Bibliotheken verwenden (Java nio, epoll, sogar node.js). Bedeutet dies, dass Async gewonnen hat?
Nicht meiner Meinung nach. Wenn beide Modelle gut implementiert sind (dies ist eine GROSSE Anforderung), denke ich, dass das Konzept von NIO vorherrschen sollte.
Im Herzen eines Computers sind Kerne. Egal, was Sie tun, Sie können Ihre Anwendung nicht mehr parallelisieren als Ihre Kerne. Wenn Sie einen 4-Kern-Rechner haben, können Sie NUR 4 Dinge gleichzeitig tun (ich beschönige hier einige Details, aber das reicht für dieses Argument).
Erweitern Sie diesen Gedanken, wenn Sie jemals mehr Threads als Kerne haben, haben Sie Verschwendung. Dieser Abfall nimmt zwei Formen an. Zuerst ist der Overhead der zusätzlichen Threads selbst. Zweitens ist die Zeit, die zwischen den Threads verbracht wird. Beide sind wahrscheinlich geringfügig, aber sie sind da.
Idealerweise haben Sie einen einzelnen Thread pro Kern und jeder dieser Threads läuft mit 100% Verarbeitungsgeschwindigkeit in seinem Kern. Aufgabenumschaltung würde im Idealfall nicht stattfinden. Natürlich gibt es das Betriebssystem, aber wenn Sie eine 16-Core-Maschine nehmen und 2-3 Threads für das Betriebssystem lassen, dann gehen die restlichen 13-14 auf Ihre App. Diese Threads können das, was sie tun innerhalb Ihrer App wechseln, etwa wenn sie durch E / A-Anforderungen blockiert werden, müssen diese Kosten jedoch nicht auf Betriebssystemebene bezahlen. Schreibe es direkt in deine App.
Ein hervorragendes Beispiel für diese Skalierung findet sich in SEDA Ссылка . Es zeigte eine viel bessere Skalierung unter Last als ein Standard-Thread-pro-Anfrage-Modell.
Meine persönliche Erfahrung ist mit Netty. Ich hatte eine einfache App. Ich habe es sowohl in Tomcat als auch in Netty gut umgesetzt. Dann habe ich es getestet mit 100 von gleichzeitig Anfragen (mehr als 800 glaube ich). Schließlich verlangsamte sich Tomcat zu einem Crawl und zeigte extrem stoßartiges / laggy Verhalten. Während die Netty-Implementierung lediglich die Reaktionszeit verlängerte, aber mit einem unglaublichen Gesamtdurchsatz fortfuhr.
Bitte beachten Sie, dass dies von einer soliden Implementierung abhängt. NIO wird immer besser mit der Zeit. Wir lernen, wie wir unsere Server-Betriebssysteme besser darauf abstimmen können und wie wir die JVMs implementieren können, um die Betriebssystemfunktionalität besser zu nutzen. Ich glaube nicht, dass ein Gewinner noch erklärt werden kann, aber ich glaube, NIO wird der spätere Gewinner sein, und es geht schon ganz gut.
Es ist schneller, solange genügend Speicher vorhanden ist.
Wenn es zu viele Verbindungen gibt, von denen die meisten im Leerlauf sind, kann NIO Threads speichern und somit Speicher sparen, und das System kann viel mehr Benutzer verwalten als ein Thread pro Verbindungsmodell.
CPU ist hier kein direkter Faktor. Mit NIO müssen Sie effektiv ein Threading-Modell selbst implementieren, das wahrscheinlich nicht schneller ist als die Threads von JVM.
In beiden Fällen ist Speicher der ultimative Flaschenhals. Wenn die Last ansteigt und der verwendete Speicher sich max. Nähert, ist GC sehr beschäftigt, und das System zeigt oft das Symptom von 100% CPU.
Vor einiger Zeit fand ich eine ziemlich interessante Präsentation , die einen Einblick gab, warum "altes Thread-pro-Client-Modell" besser ist ". Es gibt sogar Messungen. Aber ich denke immer noch darüber nach. Meiner Meinung nach ist die beste Antwort auf diese Frage "es kommt darauf an", weil die meisten (wenn nicht alle) technischen Entscheidungen Kompromisse sind.
Wie diese Präsentation sagte - es gibt Geschwindigkeit und Skalierbarkeit.
Ein Szenario, in dem Thread-pro-Anfrage mit hoher Wahrscheinlichkeit schneller ist als jede asynchrone Lösung, ist, wenn Sie eine relativ kleine Anzahl von Clients haben (z. B. & lt; 100), aber jeder Client ein sehr hohes Volumen aufweist. z.B. eine Echtzeit-App, bei der nicht mehr als 100 Clients 500 Nachrichten pro Sekunde senden / generieren. Thread-per-Request-Modell ist sicherlich effizienter als jede asynchrone Event-Loop-Lösung. Async skaliert besser, wenn viele Anforderungen / Clients vorhanden sind, da es keine Zyklen verschwendet, die auf viele Clientverbindungen warten. Wenn Sie jedoch wenige Clients mit hohem Volumen und wenig Wartezeit haben, ist es weniger effizient.
Nach dem, was ich gesehen habe, erkennen sowohl die Autoren von Node als auch Netty, dass diese Frameworks in erster Linie Skalierbarkeitssituationen mit hohen Volumina / vielen Verbindungen behandeln sollen, anstatt für eine kleinere Anzahl von Clients mit hohem Volumen schneller zu sein.
Tags und Links java multithreading pthreads nio