Früher konnte in Unix-basierten Systemen die E / A-Verarbeitung mit select () asynchron gemacht werden, und die Verarbeitung konnte nur durchgeführt werden, wenn sich der Status des Dateideskriptors änderte. Dies war (anscheinend) eine effektive Technik in einer Zeit, in der die Speicher- und Serverressourcen extrem niedrig waren. In der zweiten Hälfte der 90er und in der ersten Hälfte der 2000er Jahre wurde Multithreading zum Mainstream, und auf der Serverseite wurden Verbindungen gemultiplext, indem der Socket des Clients, der akzeptiert und akzeptiert wurde, an den Thread weitergeleitet und gesendet und empfangen wurde. (Natürlich war je nach Zweck auch asynchron aktiv)
Seit der zweiten Hälfte der 2000er Jahre macht das C10K-Problem Rauschen, und node.js und nginx sind aufgetreten. Die asynchrone Verarbeitung, die den Status von Deskriptoren überwacht, indem Sockets wieder nicht blockiert werden, wird mehr Aufmerksamkeit erregen als die Methode zum Erstellen einer großen Anzahl von Threads und zum Verbrauch von Ressourcen und Speicher. Und kürzlich sind Bibliotheken wie Javascript Promise, RX und Reactive Extension erschienen, die die asynchrone Verarbeitung an einem Ort in der Nähe der clientseitigen Benutzeroberfläche effizient beschreiben können.
Wenn jedoch eine asynchrone Verarbeitung auf der Serverseite in Betracht gezogen wird, ist es nicht möglich, Multi-Core- und Multi-CPU-Funktionen vollständig zu nutzen, indem nur asynchrone E / A-Vorgänge mit einem einzelnen Thread verarbeitet werden. Daher gibt es auch eine Methode, asynchron auf den Bereitschaftszustand des Sockets zu warten, nachdem dieser mit Accept () empfangen wurde. Wenn der Socket bereit ist, sendet und empfängt der Thread tatsächlich. Die asynchrone Verarbeitung selbst verfügt über mehrere Methoden wie select (), poll und epoll. Darüber hinaus gibt es zwei Methoden zum Multiplexen von Prozessen: Verwenden von Threads und Forking-Prozessen. Es gibt auch eine Methode, um Threads und Prozesse im Voraus zu erstellen und Daten an diese zu übergeben.
Methode | verdienen | デverdienen |
---|---|---|
select | Reduzierter Speicher- und Ressourcenverbrauch | Die Deskriptoren, die verarbeitet werden können, sind begrenzt Andere Sockets können während der Sende- / Empfangsverarbeitung eines Sockets nicht verarbeitet werden |
poll | Reduzierter Speicher- und Ressourcenverbrauch Keine Deskriptorgrenze |
Andere Sockets können während der Sende- / Empfangsverarbeitung eines Sockets nicht verarbeitet werden |
EPOLL | Schnellere Version der Umfrage Keine Deskriptorgrenze |
Andere Sockets können während der Sende- / Empfangsverarbeitung eines Sockets nicht verarbeitet werden |
fork | Nicht viele Wartesteckdosen | Hohe Prozesskosten |
thread | Nicht viele Wartesteckdosen | Verbrauchen Sie die Kosten für die Thread-Erstellung und den Verbundstapelbereich |
pre-fork | Nicht viele Wartesteckdosen Die Kosten für die Prozesserstellung fallen erst beim Start an |
Bemühungen, Daten zu übertragen, die Verarbeitung zu sperren und Prozesse zu verwalten |
pre-thread | Nicht viele Wartesteckdosen Die Kosten für die Thread-Erstellung fallen nur beim Start an |
Bemühungen um Datenübertragung, Sperrverarbeitung und Thread-Verwaltung |
EPOLL+thread | Maximale Latenz bei gleichzeitiger Reduzierung des Speicher- und Ressourcenverbrauchs | Kosten für die Thread-Erstellung. Bemühungen um Datenübertragung und Thread-Management |
EPOLL+pre thread | Maximale Latenz bei gleichzeitiger Reduzierung des Speicher- und Ressourcenverbrauchs | Der Aufwand beim Übergeben von Daten und Verwalten von Threads ist komplizierter, aber wenn er gut implementiert ist, sollte er eine perfekte Leistung bieten. |
Dieser Bereich ist "[Linux Network Programming Bible](http://www.amazon.co.jp/Linux Network Programming Bible-Mitsuyuki 1) ”ist detailliert.
Persönlich denke ich, dass "EPOLL + Thread" gut ist, aber gemäß den Benchmarks im obigen Buch hat "EPOLL + Thread" die schnellste Verbindungszeit, aber "Fork" hat die schnellste Übertragung und den schnellsten Empfang. Es scheint. In Bezug auf die Gesamtreihenfolge einschließlich der Verbindungszeit war "Pre-Thread" am schnellsten. Was das Senden und Empfangen betrifft, ist das Ergebnis, dass es schneller ist, "poll" und "EPOLL" normal zu verwenden, als spezielle Dinge wie Gabeln und Threads einschließlich "pre- ~" auszuführen (Stimmt das? ??). Übrigens steht geschrieben, dass "EPOLL + Thread" insgesamt 4. ist und langsamer als "select", "poll" und "EPOLL", aber dieses Ergebnis ist auch unglaublich.
Der Inhalt des Benchmarks scheint ein Experiment zu sein, bei dem 1000 Threads gestartet werden, indem der Verbindungsvorgang durch 50-maliges Senden und Empfangen wiederholt wird. Der Server ist ein Wählkern, und nur der send () -Teil wird eingefädelt oder gegabelt.
Wird sich die Leistung selbst dann verschlechtern, wenn Threads und Gabeln vorgeneriert sind, da Daten übertragen und Daten gesperrt werden? Ich denke, es ist durchaus möglich, dass der Punkt des Wählkerns einen Effekt hat (das Buch sagt auch, dass es sich um einen einfachen Vergleich ohne serverseitige Ressourcenüberwachung handelt).
Da "EPOLL + Pre-Thread" nicht eingeführt wird, kann dies am schnellsten sein, wenn die Anzahl der Threads in einer Multi-Core-Umgebung ordnungsgemäß unterdrückt wird. Wenn ich alleine schreibe, denke ich daran, die Anzahl der Threads mit "EPOLL + Pre-Thread" zu reduzieren.
Übrigens hat das Buch auch eine Methode zur Verarbeitung mehrerer Accepts selbst mit Threads eingeführt, aber ich kenne die Vor- und Nachteile dieser Methode nicht, da sie blockiert und einer von ihnen zum Empfänger wird.
Recommended Posts