Wir alle haben die Benchmarks gelesen und kennen die Fakten - ereignisbasierte asynchrone Netzwerkserver sind schneller als ihre Pendants mit Threads. Denken Sie Lighttpd oder Zeus gegen Apache oder IIS. Warum das?Warum sind ereignisbasierte Netzwerkanwendungen von Natur aus schneller als Threads?
Antwort
Ich denke, ereignisbasierte vs Thread basiert ist nicht die Frage - es ist eine nicht blockierende Multiplexed I/O, wählbare Sockets, Lösung vs Thread-Pool-Lösung.
Im ersten Fall behandeln Sie alle eingehenden Eingaben, unabhängig davon, was sie verwendet - also gibt es keine Blockierung für die Lesevorgänge - einen einzigen "Listener". Der einzelne Listener-Thread übergibt Daten an Workthreads unterschiedlicher Typen - und nicht an einen für jede Verbindung. Auch hier gibt es keine Blockierung beim Schreiben irgendwelcher Daten - der Datenhandler kann also einfach separat damit arbeiten. Da diese Lösung hauptsächlich IO-Lese-/Schreibvorgänge erfordert, benötigt sie nicht viel CPU-Zeit - daher kann Ihre Anwendung das tun, was sie will.
In einer Thread-Pool-Lösung haben Sie individuelle Threads, die jede Verbindung behandeln, also müssen sie Zeit für den Kontextwechsel ein- und ausschalten - jeder "zuhören". Bei dieser Lösung befinden sich die CPU + IO-Ops im selben Thread - was eine Zeitscheibe erhält -, so dass Sie auf IO-Ops pro Thread warten müssen (Blocking), was traditionell ohne CPU-Zeit möglich wäre.
Google für nicht-blockierende IO für weitere Details - und Sie können einige Vergleiche vs Thread-Pools auch finden.
(wenn jemand diese Punkte klären können, fühlen Sie sich frei)
Es geht nicht um die Fäden wirklich. Es geht darum, wie die Threads zum Bearbeiten von Anforderungen verwendet werden. Für etwas wie lighttpd haben Sie einen einzelnen Thread, der mehrere Verbindungen über Ereignisse bedient. Bei älteren Versionen von Apache hatten Sie einen Prozess pro Verbindung und der Prozess wurde bei eingehenden Daten aktiviert, so dass Sie bei sehr vielen Anfragen eine sehr große Zahl erhielten. Jetzt aber mit MPM Apache ist ereignisbasiert, siehe auch apache MPM event.
Es hängt wirklich davon ab, was Sie tun; Ereignisbasierte Programmierung ist sicherlich schwierig für nichttriviale Anwendungen. Ein Webserver zu sein ist wirklich ein sehr triviales, gut verstandenes Problem und sowohl ereignisgesteuerte als auch Threading-Modelle funktionieren ziemlich gut auf modernen Betriebssystemen.
Die korrekte Entwicklung komplexerer Serveranwendungen in einem Ereignismodell ist im Allgemeinen ziemlich schwierig - Anwendungen mit Threads lassen sich viel einfacher schreiben. Dies kann eher der entscheidende Faktor als die Leistung sein.
Ereignisgesteuerte Anwendungen sind nicht von Natur aus schneller.
Von Why Events Are a Bad Idea (for High-Concurrency Servers):
We examine the claimed strengths of events over threads and show that the
weaknesses of threads are artifacts of specific threading implementations
and not inherent to the threading paradigm. As evidence, we present a
user-level thread package that scales to 100,000 threads and achieves
excellent performance in a web server.
Das war im Jahr 2003. Denn der Zustand auf modernen Betriebssystemen von Einfädeln seitdem verbessert hat. Das Schreiben des Kerns eines ereignisbasierten Servers bedeutet, das kooperative Multitasking (Windows 3.1-Stil) in Ihrem Code neu zu erfinden, höchstwahrscheinlich auf einem Betriebssystem, das bereits korrektes präemptives Multitasking und ohne den Vorteil einer transparenten Kontextumschaltung unterstützt . Dies bedeutet, dass Sie den Status auf dem Heap verwalten müssen, der normalerweise vom Befehlszeiger impliziert oder in einer Stapelvariablen gespeichert wird. (Wenn Ihre Sprache sie hat, erleichtern Schließungen diesen Schmerz erheblich. Der Versuch, dies in C zu tun, macht viel weniger Spaß.)
Dies bedeutet auch, dass Sie alle Vorbehalte gewinnen, die kooperatives Multitasking impliziert.Wenn einer Ihrer Ereignishandler aus irgendeinem Grund eine Weile dauert, wird der Ereignis-Thread angehalten. Unzusammenhängende Anfragen verzögern sich. Selbst langwierige CPU-aufwändige Operationen müssen an anderer Stelle gesendet werden, um dies zu vermeiden. Wenn Sie über den Kern eines Servers mit hoher Gleichzeitigkeit sprechen, ist "langwierige Operation" ein relativer Begriff in der Größenordnung von Mikrosekunden für einen Server, der voraussichtlich 100.000 Anforderungen pro Sekunde verarbeiten wird. Ich hoffe, dass das virtuelle Speichersystem nie für Sie Seiten von der Festplatte ziehen muss!
Eine gute Leistung durch eine ereignisbasierte Architektur kann schwierig sein, insbesondere wenn Sie Latenz und nicht nur Durchsatz berücksichtigen. (Natürlich gibt es viele Fehler, die Sie auch mit Themen machen können Concurrency immer noch schwer..)
Ein paar wichtige Fragen für den Autor eines neuen Server-Anwendung:
- Wie Threads ausführen auf den Plattformen, die Sie heute unterstützen wollen? Werden sie dein Flaschenhals sein?
- Wenn Sie immer noch mit einer schlechten Thread-Implementierung stecken: Warum repariert niemand das?
- 1. Auflistungen aufführen, die nicht von Natur aus IEnumerable sind?
- 2. Warum sind einige Objekte nicht von verschiedenen Threads aus zugänglich?
- 3. Warum sind Listen schneller als Zeichenfelder für String-Verkettung
- 4. Sind Sitzungen schneller als Abfragen der Datenbank?
- 5. Warum int32_t schneller als int64_t?
- 6. Sind Algorithmen zum ständigen Ändern von Passwörtern eine von Natur aus schlechte Idee?
- 7. Threads sind langsam, wenn Audio aus ist
- 8. Warum führt $ a + = 3 schneller als $ a = $ a + 3 aus?
- 9. Warum sind CUDA-Vektortypen (int4, float4) schneller?
- 10. Warum kompiliert C# viel schneller als C++?
- 11. Sind PostgreSQL-Funktionen generell schneller als Code?
- 12. Warum ist string.IsNullOrEmpty schneller als ein Vergleich?
- 13. Warum Join ist schneller als normale Verkettung
- 14. Warum ist Core Data schneller als SQLite
- 15. Warum ist HashMap schneller als HashSet?
- 16. Jeder Grund UDFs wäre schneller als Makro?
- 17. die Natur des #define
- 18. Warum ist MSMQ schneller als WCF QueueService?
- 19. Warum ist float() schneller als int()?
- 20. Matrix Multiplikation mit Threads: Warum ist es nicht schneller?
- 21. Warum emplace_back ist schneller als push_back?
- 22. Warum ist ToUpperInvariant() schneller als ToLowerInvariant()?
- 23. Warum ist \% (\) schneller als \ (\) in Vim?
- 24. Warum PathPing ist schneller als Tracert?
- 25. Warum ist String.IsNullOrEmpty schneller als String.Length?
- 26. Warum ist file_get_contents() schneller als mit fsock_open()?
- 27. Warum ist String.equals() schneller als sich selbst?
- 28. Warum scheint PhoneGap schneller als Titanium?
- 29. Warum eine Union ist schneller als eine Gruppe von
- 30. Natur Join Tables
Danke für die Antwort. – dowski