Parallelität IO Das Problem war schon immer ein technisches Problem bei der serverseitigen Programmierung, von der frühesten Synchronisation, die den direkten Fork-Prozess blockierte, bis hin zum Worker-Prozesspool/Thread-Pool, zur aktuellen asynchronen E/A und Coroutine. PHP-Programmierer wegen ihrer Leistungsfähigkeit
Das LAMP-Framework verfügt über wenig Wissen über solche zugrunde liegenden Aspekte. Der Zweck dieses Artikels besteht darin, die verschiedenen Versuche von PHP zur gleichzeitigen E/A-Programmierung im Detail vorzustellen und schließlich die Verwendung von Swoole zur umfassenden Analyse gleichzeitiger E/A-Probleme auf einfache und leicht verständliche Weise vorzustellen Bedingungen.
Die frühesten serverseitigen Programme lösten das Problem der ParallelitätIO durch Multiprozess und Multithread. Das Prozessmodell erschien am frühesten, und das Konzept des Prozesses gibt es seit der Geburt des Unix-Systems. Die frühesten serverseitigen Programme sind im Allgemeinen Akzeptieren Ein Prozess wird erstellt, wenn ein Client eine Verbindung herstellt, und dann tritt der untergeordnete Prozess in die Schleife ein Synchroner Blockierungsbereich Interagieren Sie mit Clientverbindungen und senden und empfangen Sie Verarbeitungsdaten. Threads sind leichter als Prozesse und Threads teilen sich Speicherstapel, daher ist die Interaktion zwischen Threads unterschiedlich sehr einfach umzusetzen. In einem Programm wie einem Chatroom können beispielsweise Client-Verbindungen miteinander interagieren und Spieler im Chatroom können Nachrichten an jede andere Person senden. Die Implementierung im Multithread-Modus ist sehr einfach. Daten können direkt an eine Client-Verbindung im Thread gesendet werden. Der Multiprozessmodus erfordert die Verwendung komplexer Technologien wie Pipelines, Nachrichtenwarteschlangen und gemeinsam genutzten Speicher, die zusammen als Interprozesskommunikation (
IPC
) bezeichnet werden es erreichen. Codebeispiel:
Multiprozess
/
Der Prozess des Thread-Modells ist Erstellen Sie einen Socket, binden Sie den Server-Port (binden), Listening-Port (listen), in PHPChinesische Verwendungstream_socket_serverEine Funktion kann das Obige vervollständigen3 Natürlich können Sie die Sockets Erweiterung der unteren Ebene auch separat implementieren. tritt in die while-Schleife ein und blockiert in AkzeptierenVorgang, warten auf den Eingang der Client-Verbindung. Zu diesem Zeitpunkt wechselt das Programm in einen Ruhezustand, bis ein neuer Client eine Verbindung zum Server initiiert, und das Betriebssystem wird diesen Prozess aktivieren. Die Funktion accept gibt den Socket Der Hauptprozess durchläuft Fork(php:
pcntl_fork) Um einen untergeordneten Prozess zu erstellen, verwenden Sie pthread_create(php unter multi -Threading-Modell:
neuer Thread) erstellt einen untergeordneten Thread. Sofern unten nicht anders angegeben, wird der Prozess zur Darstellung des Prozess-Threads / verwendet. Nachdem der untergeordnete Prozess erfolgreich erstellt wurde, tritt er in die while-Schleife ein und blockiert in rev(php:
fread) wird aufgerufen und wartet darauf, dass der Client Daten an den Server sendet. Nach dem Empfang der Daten verarbeitet das Serverprogramm diese und verwendet dann send (php:
fwrite) sendet eine Antwort an den Client. Ein Dienst mit langer Verbindung interagiert weiterhin mit dem Client, während ein Dienst mit kurzer Verbindung im Allgemeinen schließt, sobald er eine Antwort erhält. Wenn die Clientverbindung geschlossen wird, wird der untergeordnete Prozess beendet und zerstört alle Ressourcen. Der Hauptprozess wird diesen untergeordneten Prozess recyceln. Das größte Problem bei diesem Modell ist, dass der Prozess / Thread-Erstellung und Zerstörung Die Kosten sind enorm. Daher kann das obige Modell nicht auf sehr ausgelastete Serverprogramme angewendet werden. Die entsprechende verbesserte Version löst dieses Problem. Dies ist das klassische Leader-Follower . Codebeispiel: Seine Besonderheit besteht darin, dass N Prozesse. Jeder untergeordnete Prozess tritt in Akzeptieren ein und wartet auf den Eintritt neuer Verbindungen. Wenn der Client eine Verbindung zum Server herstellt, wird einer der untergeordneten Prozesse aktiviert, beginnt mit der Verarbeitung der Client-Anfrage und akzeptiert keine neuen TCP-Verbindungen mehr. Wenn diese Verbindung geschlossen wird, wird der untergeordnete Prozess freigegeben und Akzeptieren erneut eingegeben, um an der Verarbeitung neuer Verbindungen teilzunehmen. Der Vorteil dieses Modells besteht darin, dass es den Prozess vollständig wiederverwenden kann, ohne zusätzlichen Verbrauch und mit sehr guter Leistung. Viele gängige Serverprogramme basieren auf diesem Modell, wie zum Beispiel Apache , PHP-FPM . Das Multiprozessmodell hat auch einige Nachteile. Dieses Modell hängt stark von der Anzahl der Prozesse ab, um Parallelitätsprobleme zu lösen. Eine Clientverbindung muss einen Prozess belegen, wie viele Arbeitsprozesse vorhanden sind und wie viele gleichzeitig ausgeführt werden Verarbeitungsmöglichkeiten So viele wie es gibt. Das Betriebssystem ist in der Anzahl der Prozesse, die es erstellen kann, begrenzt. Das Starten einer großen Anzahl von Prozessen führt zu einem zusätzlichen Prozessplanungsverbrauch. Wenn es Hunderte von Prozessen gibt, kann der Verbrauch der Prozesskontextwechselplanung CPUweniger als 1 % Sie können es ignorieren. Wenn Tausende oder sogar Zehntausende Prozesse gestartet werden, wird der Verbrauch sprunghaft ansteigen. Der geplante Verbrauch kann Dutzende Prozent der CPU oder sogar 100 % ausmachen . Es gibt auch einige Szenarien, die das Multiprozessmodell nicht lösen kann, wie zum Beispiel Instant-Chat-Programme (IM), ein Server muss Zehntausende oder sogar Hunderttausende oder Millionen von Verbindungen gleichzeitig aufrechterhalten (der klassische C10K Problem), das Multiprozessmodell liegt außerhalb meiner Möglichkeiten. Es gibt ein weiteres Szenario, das ebenfalls die Schwäche des Multiprozessmodells darstellt. Normalerweise startet der Web-Server 100 Prozesse, wenn eine Anfrage 100 ms, 100 Prozesse können 1000qps, diese Verarbeitungsfähigkeit ist ziemlich gut. Wenn die Anfrage jedoch den Aufruf der externen Netzwerkschnittstelle Http erfordert, z. B. QQ , die Weibo-Anmeldung dauert lange, eine Anfrage dauert 10 Sekunden. Dieser Prozess kann 1 Sekunden nur 0,1 Anfragen verarbeiten, 100 Prozesse können nur 10qps erreichen. IO innerhalb eines Prozesses bewältigen kann? Die Antwort lautet: Ja, das ist IO Wiederverwendungstechnologie. EigentlichIOVerlauf wiederverwenden So lange Als Multiprozess wird Linux schon seit langem bereitgestellt select Systemaufrufe können 1024 Verbindungen innerhalb eines Prozesses aufrechterhalten. Später wurde der Systemaufruf Umfrage hinzugefügt und einige Verbesserungen an Umfrage. Das Problem von 1024 wurde gelöst und kann eine beliebige Anzahl von Verbindungen aufrechterhalten. Aber auswählen/abfragen Ein weiteres Problem besteht darin, dass eine Schleife erforderlich ist, um zu erkennen, ob Ereignisse in der Verbindung vorliegen. Hier entsteht das Problem, wenn der Server 100 Millionen Verbindungen hat und nur eine Verbindung zu einem bestimmten Zeitpunkt Daten an den Server sendet, Auswählen/Abfragenmuss 100 zehntausend Mal wiederholt werden, davon nur 1 Mal sind Treffer, und die restlichen 9910.000 9999 Zeiten sind ungültig und verschwenden CPU Ressourcen . BisLinux 2.6 stellt der Kernel ein neues epollSystem bereit Der Anruf kann eine unbegrenzte Anzahl von Verbindungen ohne Abfrage aufrechterhalten, was das C10K -Problem wirklich löst. Heutzutage basieren verschiedene asynchrone IO Serverprogramme mit hoher Parallelität auf epoll Implementiert, wie zum Beispiel Nginx, Node.js, Erlang, Golang. Ein Single-Process- und Single-Threaded-Programm wie Node.js kann mehr als 1 MillionenTCP-Verbindungen, alles dank der epoll-Technologie. IOAsynchrone nicht blockierende Programme mit dem klassischen Reactor wiederverwenden Modell, ReaktorWie der Name schon sagt, bedeutet es Reaktor, es verarbeitet selbst keine Daten, die gesendet und empfangen werden. Es kann nur Ereignisänderungen eines Socket-Handles überwachen. ReaktorJa4 Kerngeschäft: hinzufügenSteckdose hinzufügenanhören Reaktor, kann zuhören
socket kann auch den Clientsocket oder eine Pipe, eventfd , Signale usw. einstellenEreignisüberwachung ändern, Sie können Legen Sie den Abhörtyp fest, z. B. lesbar und beschreibbar. Lesbar und leicht verständlich, zum Hören
socket bedeutet, dass eine neue Clientverbindung akzeptiert muss. Damit Clientverbindungen Daten empfangen können, ist recv erforderlich. Beschreibbare Ereignisse sind etwas schwieriger zu verstehen. Ein SOCKET verfügt über einen Cache-Bereich. Wenn Sie eine Verbindung zum Client herstellen möchten, senden Sie 2M können nicht auf einmal gesendet werden. Standardmäßig verfügt der Cache-Bereich TCP des Betriebssystems nur über 256K. Sie können jeweils nur 256K senden. Nachdem der Cache voll ist, senden Gibt den Fehler EAGAIN zurück. Zu diesem Zeitpunkt müssen Sie beschreibbare Ereignisse überwachen. Bei der reinen asynchronen Programmierung müssen Sie beschreibbare Ereignisse überwachen, um sicherzustellen, dass der Sendevorgang vollständig nicht blockierend ist . delvom Reaktor Aus der Veranstaltung entfernt und nicht mehr auf Ereignisse warten Rückruf ist die entsprechende Verarbeitungslogik nach Eintreten des Ereignisses, normalerweise in Hinzufügen/Setzen wird formuliert. C Sprache wird mit Funktionszeigern implementiert, JS kann anonyme Funktionen verwenden, PHPSie können anonyme Funktionen, Objektmethoden-Arrays und String-Funktionsnamen verwenden. Reactor ist eigentlich nur ein Ereignisgenerator Socket verarbeitet Vorgänge wie Verbinden/Akzeptieren, Senden/Empfangen, Schließen ist in Rückruf Abgeschlossen in . Informationen zur spezifischen Codierung finden Sie im folgenden Pseudocode: ReaktorDas Modell kann auch sein Bei Verwendung mit mehreren Prozessen kann durch die Kombination mehrerer Threads nicht nur asynchrones, nicht blockierendes IO erreicht, sondern auch die Vorteile mehrerer Kerne genutzt werden. Die derzeit beliebten asynchronen Serverprogramme sind alle auf diese Weise: wie zum Beispiel Nginx: Multi-Process Reaktor Nginx+Lua: MultiprozessReaktor+Coroutine Golang : EinzelthreadReaktor+Multithread-Coroutine Swoole: MultithreadedReactor+Multi- ProzessArbeiter Coroutine aus der Perspektive des zugrunde liegenden Technologie Tatsächlich handelt es sich immer noch um ein asynchrones IO-Reaktormodell. Die Anwendungsschicht implementiert die Aufgabenplanung selbst und verwendet Reactor, um jeden aktuell ausgeführten Benutzermodus-Thread zu wechseln, aber die Existenz von Reactor ist im Benutzercode völlig unsichtbar. Stream: PHP vom Kernel bereitgestellt SocketPaket Sockets: zum zugrunde liegenden Steckdose
API Wrapper Libevent: für libeventBibliothekskapselung Ereignis: basierend auf LibeventErweiterte Kapselung, die Unterstützung für objektorientierte Schnittstellen, Timer und Signalverarbeitung bietet Pcntl/Posix: Unterstützung für mehrere Prozesse, Signale und Prozessmanagement Pthread: Multithreading, Thread-Management, Sperrunterstützung PHPEs gibt auch entsprechende Erweiterungen für Shared Memory, Semaphoren und Nachrichtenwarteschlangen PECL: Erweiterungsbibliothek für PHP, einschließlich Es umfasst die unterste Schicht des Systems, Datenanalyse, Algorithmen, Treiber, wissenschaftliches Rechnen, Grafiken usw. Wenn es nicht in der Standardbibliothek PHP zu finden ist, können Sie es in PECLFunktion. Vorteile von PHP: Der erste ist die Einfachheit, PHP Es ist einfacher als jede andere Sprache. Wenn Sie anfangen möchten, PHPSie können damit wirklich loslegen eine Woche. C++Es gibt ein Buch mit dem Titel „21Days of Deep LearningC++》 Tatsächlich ist 21 unmöglich, es an einem Tag zu lernen Man kann sogar sagen, dass C++Es unmöglich ist, es gründlich zu beherrschen, ohne 3-5 Jahre. Aber PHP kann definitiv 7 Tianmen. Also PHPDie Zahl der Programmierer ist sehr groß und die Rekrutierung ist einfacher als bei anderen Sprachen. PHP ist sehr mächtig, weil PHP Der Beamte Die Standardbibliothek und die Erweiterungsbibliothek stellen 99 % der Dinge bereit, die für die Serverprogrammierung verwendet werden können. PHPs PECL-Erweiterungsbibliothek bietet alle gewünschten Funktionen. AuchPHPEs gibt mehr als 20 Jahre Geschichte, das Ökosystem ist sehr groß und man kann viel Code auf Github finden. Nachteile von PHP: Die Leistung ist relativ schlecht, da es sich schließlich um ein dynamisches Skript handelt und nicht für intensive Berechnungen geeignet ist PHP-Programm
C/C++ ist in geschrieben, die PHP -Version ist schlechter als es Hundertmal. Jeder weiß, dass die Funktionsnamenskonvention schlecht ist, PHP Es zahlt sich mehr aus Der Schwerpunkt liegt auf der Praktikabilität und es gibt keine Vorschriften. Die Benennung einiger Funktionen ist sehr verwirrend, sodass Sie jedes Mal im Handbuch von PHP nachschlagen müssen. Die Schnittstellengranularität der von bereitgestellten Datenstrukturen und Funktionen ist relativ grob. PHP hat nur eine Array Datenstruktur, auf der die zugrunde liegende Schicht basiert HashTable. PHPs Array zusammengestellt Karte, Satz, Vektor , Warteschlange, Stapel, Funktionen von Datenstrukturen wie Heap. Darüber hinaus verfügt PHP über eine SPL Also PHP PHP PHP mit C/C++, JAVA, Golang und andere statisch kompilierte Sprachen dienen als Ergänzung zu PHP Verwenden Sie das IDE basiert auf der oben genannten Erweiterung unter Verwendung von reinem PHP Sie können asynchrone Netzwerkserver- und Clientprogramme vollständig implementieren. Wenn Sie jedoch einen Thread implementieren möchten, der mehreren IO ähnelt, müssen Sie noch viel mühsame Programmierarbeit erledigen, einschließlich der Art und Weise, wie Verbindungen verwaltet werden um das Senden und Empfangen von Daten zu gewährleisten, Verarbeitung von Netzwerkprotokollen. Darüber hinaus PHPDie Leistung des Codes im Protokollverarbeitungsteil ist relativ schlecht, daher habe ich ein neues Open-Source-Projekt gestartet Swoole , unter Verwendung der Sprache C und PHPKombiniert hat den Job gemacht. Flexible und veränderbare Geschäftsmodule verwenden PHP für eine hohe Entwicklungseffizienz, und die grundlegenden zugrunde liegenden und Protokollverarbeitungsteile verwenden C Die Sprachimplementierung sorgt für eine hohe Leistung. Es wird in erweiterter Form in PHP geladen, um ein vollständiges Netzwerkkommunikations-Framework bereitzustellen, und dann in PHP Code zum Schreiben eines Geschäfts. Sein Modell basiert auf MultithreadingReactor+MultiprozessWorker, Dies unterstützt sowohl vollständig asynchron als auch semi-asynchron und semi-synchron. Einige Funktionen von AkzeptierenThread, lösen AkzeptierenLeistungsengpass und donnerndes Gruppenproblem MehrereIOThreads können Multi-Cores besser nutzen Bereitstellung vollständig asynchroner und halbsynchroner und halbasynchroner2Modi Asynchroner Modus wird für die Handhabung hoher Parallelität verwendetIO komplexer Geschäftslogikteil Synchronmodus Die unterste Ebene unterstützt das Durchlaufen aller Verbindungen, das gegenseitige Senden von Daten, das automatische Zusammenführen und Aufteilen von Datenpaketen sowie das atomare Senden von Daten. Der Beispielcode befindet sich unter https://github.com/swoole/swoole-src Homepage-Check. AsynchronTCPServer: Hierneuer swoole_server Objekt, dann Die Parameter werden an den überwachten HOST und PORT übergeben, und dann 3 Callback-Funktionen eingestellt, nämlich onConnect wenn eine neue Verbindung zustande kommt, onReceiveDaten von einem bestimmten Client empfangen, onCloseEin bestimmter Client ist geschlossen . Rufen Sie abschließend start auf, um das Serverprogramm zu starten. swooleDie untere Schicht beginnt entsprechend der Anzahl der CPU Kerne Die aktuelle Maschine verfügt über eine Anzahl von Reactor Threads und Worker Prozessen. Asynchroner Client: Die Verwendung des Clients ist mit der Ausnahme des Servers ähnlich Es gibt Rückrufereignisse4, onConnect erfolgreich mit dem Server verbunden, dann Sie können Daten an den Server senden. onErrorVerbindung zum Server fehlgeschlagen. onReceiveDer Server hat Daten an die Client-Verbindung gesendet. onCloseDie Verbindung wird geschlossen. Nachdem Sie den Ereignisrückruf festgelegt haben, initiieren Sie eine Verbindung zum Server. Die Parameter sind die des Servers IP, PORT und Timeout. Synchronisierungsclient: Sync The Der Client muss keine Ereignisrückrufe festlegen. Er verfügt nicht über einen Reactor und blockiert seriell. Warten Sie, bis IO abgeschlossen ist, bevor Sie mit dem nächsten Schritt fortfahren. Asynchrone Aufgaben: Die asynchrone Task-Funktion wird verwendet, um eine zeitaufwendige oder blockierende Funktion in einem rein asynchronen Server-Programm auszuführen. Die zugrunde liegende Implementierung verwendet einen Prozesspool, nachdem die Aufgabe abgeschlossen ist. onFinish wird ausgelöst und die Ergebnisse der Aufgabenverarbeitung können im Programm abgerufen werden. Beispielsweise muss eine IM gesendet werden, wenn sie direkt im asynchronen Code gesendet wird, kann dies Auswirkungen auf die Verarbeitung anderer Ereignisse haben. Darüber hinaus kann das Lesen und Schreiben von Dateien auch über asynchrone Aufgaben implementiert werden, da Dateihandles nicht wie socket wie ReaktorÜberwachung. Da das Dateihandle immer lesbar ist, kann das direkte Lesen der Datei das Serverprogramm blockieren. Die Verwendung asynchroner Aufgaben ist eine sehr gute Wahl. Asynchroner Millisekunden-Timer Dies 2 Schnittstellen implementieren ähnliche JSsetInterval , setTimeout Funktionsfunktion kann in n implementiert werden Funktion in Millisekundenintervallen ausführen oder eine Funktion nach n Millisekunden ausführen. AsynchronMySQLClient swoole bietet auch einen integrierten Verbindungspool MySQL asynchronen Client, der kann die maximale Anzahl von MySQL-Verbindungen festlegen. Gleichzeitige SQL-Anfragen können diese Verbindungen wiederverwenden, anstatt sie wiederholt zu erstellen, was MySQLVermeiden Sie eine Erschöpfung der Verbindungsressourcen. AsynchronRedisClient AsynchronWeb Programm Die Logik des Programms stammt von Redis und zeigen Sie dann die Seite HTML an. Mit ab ist die Druckmessleistung wie folgt: php-fpm wie folgt: WebSocketProgramm swoole verfügt über einen integrierten Websocket Server, der basierend implementiert werden kann auf diesem Web Die Funktion des aktiven Seitenpushs, wie z. B. WebIM. Es gibt ein Open-Source-Projekt, das als Referenz verwendet werden kann. https://github.com/matyhtf/php-webim Asynchrone Programmierung verwendet im Allgemeinen Rückrufe. Wenn Sie auf sehr komplexe Logik stoßen, können Rückruffunktionen Schicht für Schicht verschachtelt sein. Coroutinen können dieses Problem lösen. Code kann sequentiell geschrieben werden, die Laufzeit ist jedoch asynchron und nicht blockierend. Die Ingenieure von Tencent basieren auf der Erweiterung Swoole und PHP5.5s Die Syntax Yield/Generator implementiert eine Coroutine ähnlich wie Golang, der Projektname lautet TSF(Tencent
Server Framework), Open-Source-Projektadresse: https://github.com/tencent-php/tsf. Derzeit in Tencents Unternehmen QQ, QQ Public-Account-Projekte und Räder Ignorierte Artikel zur Kontrolle von Verkehrsverstößen werden in großem Umfang eingesetzt
. TSF ist auch sehr einfach zu verwenden. Die folgenden Aufrufe 3IO Operationen sind vollständig serialisiert. Tatsächlich wird es jedoch asynchron und nicht blockierend ausgeführt. TSFDer zugrunde liegende Scheduler übernimmt die Ausführung des Programms, im entsprechenden IO Nach Abschluss wird die Ausführung nach unten fortgesetzt.
IOWiederverwendung/Ereignisschleife /Asynchrone Nichtblockierung
Was ist Coroutine
PHP Concurrent IO Programming Practice
PHPVerwandte Erweiterungen
PHPVor- und Nachteile der Sprache
PHPs Swoole-Erweiterung
Swoole:
SwooleProzess/Einfädelmodell:
SwooleProgrammausführungsablauf:
Verwenden Sie die Erweiterung PHP+Swoole, um asynchrone Kommunikationsprogrammierung zu implementieren
TCPServer und Client
PHP+SwooleCoroutinen
Das obige ist der detaillierte Inhalt vonDetaillierte Erläuterung der gleichzeitigen PHP-IO-Programmierung. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!