Inhaltsverzeichnis- 1. Einführung in grundlegende Konzepte
- 2. Netzwerk-E/A-Lese- und Schreibvorgang
- 3. Fünf Linux-Netzwerk-IO-Modelle
- 3.1 Blockieren von E/A
- 3.2 Nicht blockierende IO
- 3.3. Multiplexen von E/A (IO-Multiplexing)
- 3.4 Signalgesteuerte E/A (SIGIO)
- 3.5. Asynchrone IO (POSIX aio_-Reihenfunktionen)
- 4. Ein tiefes Verständnis von Multiplexed IO
- 4.1, auswählen
- 4.2, epoll
- 4.3. Vorteile von epoll gegenüber select
- 4.4. Fragen dazu, ob das Epoll-IO-Modell synchron oder asynchron ist
- 5. Reaktormodell
- 5.1. Einführung in verwandte Konzepte
- 5.2. Allgemeiner Reaktorprozess
- 5.3. Einzelner Thread + Reaktor
- 5.4 Multithreading + Reaktor
- 5.5. Multithreading + Mehrere Reaktoren
- 6. Allgemeiner Prozess des Proactor-Modells
- 6.1. Unterschiede zwischen Proactor und Reactor
1. Einführung in grundlegende Konzepte- Prozess- (Thread-)Umschaltung: Alle Systeme verfügen über die Möglichkeit, Prozesse zu planen, wodurch ein aktuell laufender Prozess angehalten und der zuvor angehaltene Prozess fortgesetzt werden kann.
- Blockieren von Prozessen (Threads): Ein laufender Prozess wartet manchmal auf den Abschluss anderer Ereignisse, z. B. auf eine Sperre oder auf die Anforderung von E/A-Lese- und Schreibvorgängen. Das System blockiert den Prozess automatisch, während er wartet, und der Prozess belegt nicht die CPU.
- Dateideskriptor: Unter Linux ist ein Dateideskriptor ein abstraktes Konzept, das zur Beschreibung eines Verweises auf eine Datei verwendet wird, bei der es sich um eine nicht negative Ganzzahl handelt. Wenn ein Programm eine vorhandene Datei öffnet oder eine neue Datei erstellt, gibt der Kernel einen Dateideskriptor an den Prozess zurück.
- Linux-Signalverarbeitung: Linux-Prozesse können während des Betriebs Signalwerte vom System oder Prozess empfangen und dann die entsprechende Erfassungsfunktion entsprechend dem Signalwert ausführen. Das Signal entspricht der Softwaresimulation des Hardware-Interrupts
Im Kapitel zum Zero-Copy-Mechanismus haben wir Benutzerspeicherplatz, Kernelspeicherplatz und Puffer vorgestellt, deshalb werden wir diese hier auslassen. 2. Netzwerk-E/A-Lese- und Schreibvorgang- Wenn im Benutzerbereich ein Lesevorgang auf einem Socket initiiert wird, erfolgt ein Kontextwechsel. Der Benutzerprozess blockiert (R1) und wartet auf das Eintreffen des Netzwerkdatenstroms und kopiert ihn von der Netzwerkkarte in den Kernel (R2) und kopiert ihn dann vom Kernelpuffer in den Benutzerprozesspuffer. Zu diesem Zeitpunkt wechselt der Prozess und setzt die Verarbeitung der erhaltenen Daten fort
- Hier geben wir der ersten Stufe des Socket-Lesevorgangs den Alias R1 und der zweiten Stufe den Namen R2.
- Wenn ein Sendevorgang an einem Socket im Benutzerbereich initiiert wird, erfolgt ein Kontextwechsel und der Benutzerprozess blockiert und wartet (1), bis Daten aus dem Benutzerprozesspuffer in den Kernelpuffer kopiert werden. Das Kopieren der Daten ist abgeschlossen und der Prozessschalter wird wiederhergestellt.
3. Fünf Linux-Netzwerk-IO-Modelle 3.1 Blockieren von E/A
ssize_t recvfrom(int sockfd, void *buf, size_t len, vorzeichenlose int-Flags, Struktur sockaddr *from, socket_t *fromlen); 
- Das grundlegendste E/A-Modell ist das blockierende E/A-Modell, das zugleich auch das einfachste Modell ist. Alle Operationen werden nacheinander ausgeführt
- Im blockierenden IO-Modell führt die Anwendung im Benutzerbereich einen Systemaufruf (recvform) aus, der dazu führt, dass die Anwendung blockiert wird, bis die Daten im Kernelpuffer bereit sind und die Daten vom Kernel in den Benutzerprozess kopiert werden. Der letzte Prozess wird vom System aufgeweckt, um die Daten zu verarbeiten
- In zwei aufeinanderfolgenden Phasen, R1 und R2, wird der gesamte Prozess blockiert.
3.2 Nicht blockierende IO 
- Nicht blockierende IO ist auch eine Art synchroner IO. Die Implementierung basiert auf einem Polling-Mechanismus, bei dem der Socket blockierend geöffnet wird. Dies bedeutet, dass die E/A-Operation nicht sofort abgeschlossen wird, sondern einen Fehlercode (EWOULDBLOCK) zurückgibt, der angibt, dass die Operation nicht abgeschlossen wurde.
- Führen Sie eine Abfrage durch, um die Kerneldaten zu prüfen und geben Sie EWOULDBLOCK zurück, wenn die Daten nicht bereit sind. Der Prozess fährt mit der Initiierung des Recvfrom-Anrufs fort. Natürlich können Sie ihn pausieren, um andere Dinge zu tun.
- Bis die Kerneldaten bereit sind, werden die Daten in den Benutzerbereich kopiert. Anschließend ruft der Prozess die Daten ohne Fehlercode ab und fährt mit der Verarbeitung der Daten fort. Es ist zu beachten, dass sich der Vorgang während des gesamten Kopiervorgangs der Daten noch in einem blockierten Zustand befindet.
- Der Prozess ist in der R2-Phase blockiert. Obwohl er in der R1-Phase nicht blockiert ist, muss er kontinuierlich abgefragt werden.
3.3. Multiplexen von E/A (IO-Multiplexing) 
- Im Allgemeinen gibt es im Backend-Dienst eine große Anzahl von Socket-Verbindungen. Wenn Sie den Lese- und Schreibstatus mehrerer Sockets gleichzeitig abfragen und verarbeiten können, wenn einer bereit ist, ist die Effizienz viel höher. Dies ist „E/A-Multiplexing“. Multiplexing bezieht sich auf mehrere Sockets, und Multiplexing bezieht sich auf das Multiplexen desselben Prozesses.
- Linux bietet Multiplex-E/A-Implementierungen wie select, poll und epoll
- select oder poll, epoll blockieren Anrufe
- Im Gegensatz zum Blockieren von IO wartet select nicht, bis alle Socket-Daten eingetroffen sind, bevor es die Verarbeitung vornimmt, sondern setzt den Benutzerprozess zur Verarbeitung fort, sobald einige Socket-Daten bereitstehen. Woher wissen Sie, dass einige Daten im Kernel bereitstehen? Antwort: Überlassen Sie dies dem System.
- Der Prozess wird auch in den Phasen R1 und R2 blockiert. Allerdings gibt es in der Phase R1 einen Trick. In einer Multiprozess- und Multithread-Programmierumgebung können wir nur einen Prozess (Thread) zuweisen, der den Aufruf von select blockiert, sodass andere Threads freigegeben werden können.
3.4 Signalgesteuerte E/A (SIGIO) 
- Es muss eine Signalerfassungsfunktion bereitgestellt und mit dem Socket verknüpft werden. Nach dem Initiieren des Sigaction-Aufrufs kann der Prozess freigegeben werden, um andere Dinge zu erledigen.
- Wenn die Daten im Kernel bereit sind, empfängt der Prozess ein SIGIO-Signal, unterbricht es dann, um die Signalerfassungsfunktion auszuführen, ruft recvfrom auf, um die Daten vom Kernel in den Benutzerbereich zu lesen, und verarbeitet dann die Daten
- Es ist ersichtlich, dass der Benutzerprozess in der R1-Phase nicht blockiert wird, R2 jedoch weiterhin blockiert bleibt und wartet
3.5. Asynchrone IO (POSIX aio_-Reihenfunktionen) 
- Im Vergleich zu synchronem IO blockiert asynchrones IO den aktuellen Prozess nicht, nachdem der Benutzerprozess einen Systemaufruf zum asynchronen Lesen (aio_read) initiiert hat, unabhängig davon, ob die Kernelpufferdaten bereit sind. Der Prozess kann nach der Rückkehr des Systemaufrufs aio_read andere Logik verarbeiten.
- Wenn die Socket-Daten im Kernel bereit sind, kopiert das System die Daten direkt vom Kernel in den Benutzerbereich und benachrichtigt dann den Benutzerprozess über ein Signal
- Die Prozesse in den Phasen R1 und R2 sind nicht blockierend.
4. Ein tiefes Verständnis von Multiplexed IO 4.1, auswählen
int auswählen(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, Struktur timeval *timeout); 1) Verwenden Sie copy_from_user, um fd_set vom Benutzerbereich in den Kernelbereich zu kopieren 2) Registrieren Sie die Rückruffunktion __pollwait 3) Durchlaufen Sie alle FDS und rufen Sie ihre entsprechenden Polling-Methoden auf (für Sockets ist diese Polling-Methode sock_poll, sock_poll ruft je nach Situation tcp_poll, udp_poll oder datagram_poll auf). 4) Am Beispiel von tcp_poll lautet die Kernimplementierung __pollwait, die oben registrierte Rückruffunktion 5) Die Hauptaufgabe von __pollwait besteht darin, current (den aktuellen Prozess) in der Warteschlange des Geräts zu halten. Verschiedene Geräte haben unterschiedliche Warteschlangen. Für tcp_poll lautet die Warteschlange sk->sk_sleep (beachten Sie, dass das Halten eines Prozesses in der Warteschlange nicht bedeutet, dass der Prozess in den Ruhezustand gegangen ist). Nachdem das Gerät eine Nachricht empfangen (Netzwerkgerät) oder die Dateidaten eingegeben hat (Festplattengerät), wird der schlafende Prozess in der Warteschlange des Geräts geweckt und der aktuelle Prozess wird aufgeweckt. 6) Wenn die Poll-Methode zurückkehrt, gibt sie eine Maske zurück, die beschreibt, ob die Lese- und Schreibvorgänge bereit sind. Gemäß dieser Maske wird fd_set ein Wert zugewiesen. 7) Wenn alle fds durchlaufen wurden und keine lesbare und beschreibbare Maske zurückgegeben wurde, wird schedule_timeout aufgerufen, um den Prozess, der select aufgerufen hat (also den aktuellen), in den Ruhezustand zu versetzen. 8) Wenn die eigenen Ressourcen des Gerätetreibers lesbar und beschreibbar werden, weckt er den schlafenden Prozess in seiner Warteschlange. Wenn nach einer bestimmten Zeitüberschreitung (durch Timeout angegeben) niemand aufwacht, wird der Prozess, der select aufruft, erneut aufgeweckt, um die CPU zu erhalten, und dann den FD erneut durchlaufen, um festzustellen, ob ein bereiter FD vorhanden ist 9) Kopieren Sie fd_set vom Kernel-Speicher in den Benutzer-Speicher. Nachteile von select: - Bei jedem Aufruf von select muss der FD-Satz vom Benutzerstatus in den Kernelstatus kopiert werden. Dieser Aufwand ist sehr groß, wenn viele FDs vorhanden sind.
- Gleichzeitig erfordert jeder Aufruf von select, dass der Kernel alle übergebenen FDS durchläuft, was bei vielen FDS sehr aufwändig ist.
- Die Anzahl der von select unterstützten Dateideskriptoren ist zu gering, der Standardwert ist 1024
4.2, epoll
int epoll_create(int Größe);
int epoll_ctl(int epfd, int op, int fd, Struktur epoll_event *Ereignis);
int epoll_wait(int epfd, Struktur epoll_event *Ereignisse, int maxevents, int Timeout); - Wenn epoll_create aufgerufen wird, wird im Kernel-Cache ein Rot-Schwarz-Baum erstellt, um die von epoll_ctl in Zukunft gesendeten Sockets zu speichern. Gleichzeitig wird eine bidirektionale verknüpfte Rdllist-Liste erstellt, um bereite Ereignisse zu speichern. Wenn epoll_wait aufgerufen wird, überprüfen Sie einfach die Daten der bidirektionalen verknüpften Liste rdlist
- Wenn epoll_ctl Ereignisse zu einem Epoll-Objekt hinzufügt, ändert oder löscht, arbeitet es im RBR-Rot-Schwarz-Baum, der sehr schnell ist.
- Zu epoll hinzugefügte Ereignisse stellen eine Rückrufbeziehung mit dem Gerät (z. B. einer Netzwerkkarte) her. Wenn das entsprechende Ereignis auf dem Gerät auftritt, wird die Rückrufmethode aufgerufen und das Ereignis der bidirektionalen verknüpften Liste rdlist hinzugefügt. Diese Rückrufmethode wird im Kernel ep_poll_callback genannt.
Zwei Triggermodi von Epoll: epoll hat zwei Triggermodi: EPOLLLT und EPOLLET. LT ist der Standardmodus und ET der „High-Speed“-Modus (unterstützt nur No-Block-Sockets). - Im LT-Modus (Level Trigger) löst jedes epoll_wait sein Leseereignis aus, solange Daten aus diesem Dateideskriptor gelesen werden müssen
- Im ET-Modus (Flanken-Trigger) wird bei Erkennung eines E/A-Ereignisses der Dateideskriptor mit Ereignisbenachrichtigung durch den Aufruf epoll_wait abgerufen. Wenn der Dateideskriptor lesbar ist, muss er gelesen werden, bis er leer ist (oder EWOULDBLOCK zurückgegeben wird), andernfalls löst der nächste epoll_wait das Ereignis nicht aus.
4.3. Vorteile von epoll gegenüber select Beheben Sie drei Mängel von select: - Zum ersten Mangel: Die Lösung von epoll liegt in der Funktion epoll_ctl. Jedes Mal, wenn ein neues Ereignis für den Epoll-Handle registriert wird (geben Sie EPOLL_CTL_ADD in epoll_ctl an), werden alle FDS in den Kernel kopiert, anstatt während epoll_wait wiederholt kopiert zu werden. epoll stellt sicher, dass jedes fd während des gesamten Prozesses nur einmal kopiert wird (epoll_wait erfordert kein Kopieren)
- Zum zweiten Nachteil: epoll gibt für jedes FD eine Rückruffunktion an. Wenn das Gerät bereit ist und den Kellner in der Warteschlange aufweckt, wird die Rückruffunktion aufgerufen und die Rückruffunktion fügt das bereite FD einer Bereitschaftsliste hinzu. Die Aufgabe von epoll_wait besteht eigentlich darin, zu prüfen, ob sich in dieser Bereitschaftsliste ein bereiter FD befindet (kein Durchlaufen erforderlich).
- Der dritte Nachteil: Epoll hat diese Einschränkung nicht. Die Obergrenze des von ihm unterstützten FD ist die maximale Anzahl geöffneter Dateien. Diese Zahl ist im Allgemeinen viel größer als 2048. Auf einem Computer mit 1 GB Speicher sind es beispielsweise etwa 100.000. Im Allgemeinen hängt diese Zahl eng mit dem Systemspeicher zusammen.
Hohe Leistung von Epoll: - epoll verwendet einen Rot-Schwarz-Baum, um die zu überwachenden Dateideskriptorereignisse zu speichern, und epoll_ctl fügt Dateien schnell hinzu, löscht und ändert sie.
- epoll kann den bereiten FD ohne Durchlauf abrufen und direkt zur Bereitschaftsliste zurückkehren
- Nach Linux 2.6 wird die mmap-Technologie verwendet, und Daten müssen nicht mehr vom Kernel in den Benutzerbereich kopiert werden, Nullkopie
4.4. Fragen dazu, ob das Epoll-IO-Modell synchron oder asynchron ist Konzeptdefinition: - Synchrone E/A-Operationen: bewirken, dass der anfordernde Prozess blockiert wird, bis die E/A-Operation abgeschlossen ist
- Asynchroner E/A-Vorgang: führt nicht dazu, dass der Anforderungsprozess blockiert wird. Der asynchrone Vorgang verarbeitet nur die Benachrichtigung, nachdem der E/A-Vorgang abgeschlossen ist, und liest oder schreibt keine Daten aktiv. Der Systemkernel schließt das Lesen und Schreiben der Daten ab.
- Blockieren, nicht blockieren: ob die vom Prozess/Thread abzurufenden Daten bereit sind, ob der Prozess/Thread warten muss
Das Konzept der asynchronen E/A erfordert nicht blockierende E/A-Aufrufe. Wie bereits erwähnt, sind E/A-Vorgänge in zwei Phasen unterteilt: R1 wartet, bis die Daten bereit sind. R2 kopiert Daten vom Kernel in den Prozess. Obwohl epoll nach dem 2.6-Kernel den mmap-Mechanismus verwendet, wodurch die Replikation in der R2-Phase überflüssig wird, ist es in R1 immer noch blockiert. Daher wird es als synchrones IO klassifiziert. 5. Reaktormodell Die Kernidee von Reactor besteht darin, alle zu verarbeitenden E/A-Ereignisse auf einem zentralen E/A-Multiplexer zu registrieren und den Hauptthread/-prozess auf dem Multiplexer zu blockieren. Sobald ein E/A-Ereignis eintrifft oder bereit ist, kehrt der Multiplexer zurück und verteilt die entsprechenden, im Voraus registrierten E/A-Ereignisse an die entsprechenden Prozessoren. 5.1. Einführung in verwandte Konzepte- Ereignis: ist ein Zustand. Das Ereignis „Lesebereit“ bezieht sich beispielsweise auf den Zustand, in dem wir Daten aus dem Kernel lesen können.
- Ereignistrennzeichen: Im Allgemeinen wird das Warten auf Ereignisse an epoll und select übergeben. Das Eintreffen von Ereignissen ist zufällig und asynchron, sodass epoll zyklisch aufgerufen werden muss. Das entsprechende gekapselte Modul im Framework ist das Ereignistrennzeichen (einfach als Kapselung von epoll verstanden).
- Ereignishandler: Wenn ein Ereignis eintritt, wird ein Prozess oder Thread benötigt, um es zu verarbeiten. Dieser Handler ist der Ereignishandler, der normalerweise ein anderer Thread als der Ereignistrenner ist.
5.2. Allgemeiner Reaktorprozess 1) Die Anwendung registriert das Read-Write-Ready-Ereignis und den Read-Write-Ready-Eventhandler im Event-Separator 2) Der Ereignistrenner wartet auf das Auftreten des Ereignisses „Read-Write Ready“ 3) Das Ereignis „ready-write ready“ tritt ein und aktiviert den Ereignisseparator, der den Ereignishandler „ready-write ready“ aufruft. 4) Der Event-Handler liest die Daten zunächst vom Kernel in den User Space und verarbeitet sie dann 
5.3. Einzelner Thread + Reaktor 
5.4 Multithreading + Reaktor 
5.5. Multithreading + Mehrere Reaktoren 
6. Allgemeiner Prozess des Proactor-Modells 1) Die Anwendung registriert das Leseabschlussereignis und den Leseabschlussereignishandler im Ereignistrennzeichen und sendet eine asynchrone Leseanforderung an das System 2) Der Ereignistrenner wartet auf den Abschluss des Leseereignisses 3) Während der Separator wartet, führt das System mithilfe paralleler Kernel-Threads den eigentlichen Lesevorgang aus, kopiert die Daten in den Prozesspuffer und benachrichtigt schließlich den Ereignisseparator, dass der Lesevorgang abgeschlossen ist. 4) Der Ereignistrenner überwacht das Leseabschlussereignis und aktiviert den Handler des Leseabschlussereignisses 5) Der Leseabschluss-Ereignishandler verarbeitet die Daten direkt im Benutzerprozesspuffer 
6.1. Unterschiede zwischen Proactor und Reactor- Proactor basiert auf dem Konzept der asynchronen E/A, während Reactor im Allgemeinen auf dem Konzept der Multiplex-E/A basiert.
- Proactor muss keine Daten vom Kernel in den Benutzerbereich kopieren, dieser Schritt wird vom System ausgeführt
Oben finden Sie ausführliche Informationen zur Analyse des Linux-Hochleistungsnetzwerk-IO- und Reaktormodells. Weitere Informationen zum Linux-Hochleistungsnetzwerk-IO- und Reaktormodell finden Sie in den anderen verwandten Artikeln auf 123WORDPRESS.COM! Das könnte Sie auch interessieren:- Eine detaillierte Einführung in Linux IO
- Tutorial zur Verwendung des iostat-Befehls unter Linux
- Linux IO-Multiplexing Epoll-Netzwerkprogrammierung
- Interessante Erklärung des Socket IO-Modells von Linux
- Eine detaillierte Einführung in die fünf IO-Modelle unter Linux
|