Explication détaillée de la programmation d'E/S simultanées PHP

小云云
Libérer: 2023-03-21 21:56:02
original
1874 Les gens l'ont consulté

Concurrence IO Le problème a toujours été un problème technique dans la programmation côté serveur, depuis la première synchronisation bloquant le processus Fork direct jusqu'au Pool de processus de travail/pool de threads, vers les E/S asynchrones et la coroutine actuelles. Programmeurs PHP en raison de leur puissance Le framework LAMP a peu de connaissances sur ces aspects sous-jacents.Le but de cet article est de présenter en détail les différentes tentatives de programmation d'E/S simultanées de PHP, et enfin de présenter l'utilisation de Swoole pour analyser de manière exhaustive les problèmes d'E/S simultanées de manière simple et facile à comprendre. termes.

Multi-processus/Blocage de la synchronisation multi-thread

Les premiers programmes côté serveur ont résolu le problème de la concurrenceIO via multi-processus et multi-thread. Le modèle de processus est apparu le plus tôt et le concept de processus existe depuis la naissance du système Unix. Les premiers programmes côté serveur sont généralement Accepter Un processus est créé lorsqu'un client se connecte, puis le processus enfant entre dans la boucle zone de blocage synchrone Interagissez avec les connexions client et envoyez et recevez des données de traitement. Le mode multithread est apparu plus tard. Les threads sont plus légers que les processus, et les threads partagent des piles de mémoire, ils sont donc différents. très simple à mettre en œuvre. Par exemple, dans un programme tel qu'un salon de discussion, les connexions des clients peuvent interagir les unes avec les autres et les joueurs du salon de discussion peuvent envoyer des messages à n'importe quelle autre personne. C'est très simple à mettre en œuvre en mode multi-thread. Les données peuvent être envoyées directement à une connexion client dans le thread. Le mode multi-processus nécessite l'utilisation de pipelines, de files d'attente de messages, de mémoire partagée, collectivement appelés technologies complexes de communication inter-processus (

IPC

) pour réaliser il. Exemple de code :

Multi-processus

/

Le processus du modèle de fil est

  1. Créez un socket, liez le port du serveur (bind), port d'écoute (écouter), en PHPUtilisation du chinoisstream_socket_serverUne fonction peut compléter ce qui précède3 Bien sûr, vous pouvez également utiliser l'extension sockets du niveau inférieur pour les implémenter séparément.

  2. entre dans la boucle while, bloquant dans accepter l'opération, en attendant l'arrivée de la connexion client. À ce moment-là, le programme entrera en état de veille jusqu'à ce qu'un nouveau client initie une connexion au serveur, et le système d'exploitation réveillera ce processus. La fonction accepter renvoie la socket

  3. Le processus principal passe par fork(php : pcntl_fork) pour créer un processus enfant, utilisez pthread_create(php sous multi -modèle de filetage : new Thread) crée un fil de discussion enfant. Sauf indication contraire ci-dessous, le processus sera utilisé pour représenter le fil de discussion /.

  4. Une fois que le processus enfant est créé avec succès, il entre dans la boucle while, bloquant dans recv(php: fread) est appelé et attend que le client envoie des données au serveur. Après avoir reçu les données, le programme serveur les traite puis utilise send (php : fwrite) envoie une réponse au client. Un service de connexion longue continuera à interagir avec le client, tandis qu'un service de connexion courte se fermera dès réception d'une réponse.

  5. Lorsque la connexion client est fermée, le processus enfant se termine et détruit toutes les ressources. Le processus principal recyclera ce processus enfant.

Le plus gros problème avec ce modèle est que le processus / création de fil et destruction Le coût est énorme. Le modèle ci-dessus ne peut donc pas être appliqué à des programmes serveur très chargés. La version améliorée correspondante résout ce problème. Il s'agit du modèle classique Leader-Follower .

Exemple de code :

Sa caractéristique est qu'il créera N processus. Chaque processus enfant entre dans Accepter et attend que de nouvelles connexions entrent. Lorsque le client se connecte au serveur, l'un des processus enfants sera réveillé, commencera à traiter la demande du client et n'acceptera plus de nouvelles connexions TCP. Lorsque cette connexion est fermée, le processus enfant sera libéré et entrera à nouveau Accepter pour participer au traitement des nouvelles connexions.

L'avantage de ce modèle est qu'il permet de réutiliser totalement le procédé, sans consommation supplémentaire et avec un très bon rendement. De nombreux programmes serveur courants sont basés sur ce modèle, tels que Apache , PHP-FPM .

Le modèle multi-processus présente également certains inconvénients.

  1. Ce modèle s'appuie fortement sur le nombre de processus pour résoudre les problèmes de concurrence. Une connexion client doit occuper un processus, le nombre de processus de travail et un traitement simultané. capacités Autant qu'il y en a. Le système d'exploitation est limité dans le nombre de processus qu'il peut créer.

  2. Le démarrage d'un grand nombre de processus entraînera une consommation supplémentaire de planification de processus. Lorsqu'il y a des centaines de processus, la consommation de planification de changement de contexte de processus peut représenter CPUmoins de 1 % Vous pouvez l'ignorer. Si des milliers, voire des dizaines de milliers de processus sont lancés, la consommation montera en flèche. La consommation de planification peut représenter des dizaines de pour cent de CPU ou même 100 % .

Il existe également certains scénarios que le modèle multi-processus ne peut pas résoudre, comme les programmes de chat instantané (IM), un serveur doit maintenir des dizaines de milliers voire des centaines de milliers ou des millions de connexions en même temps (le classique C10K problème), le modèle multi-processus est au-delà de mes capacités.

Il existe un autre scénario qui constitue également la faiblesse du modèle multi-processus. Généralement, le serveur Web démarre 100 processus si une requête consomme 100 ms, 100 les processus peuvent fournir 1000qps, cette capacité de traitement est plutôt bonne. Mais si la demande nécessite d'appeler l'interface Http du réseau externe, comme QQ , La connexion à Weibo prendra beaucoup de temps, une demande prend 10s. Ce processus 1 secondes ne peut traiter que 0,1 requêtes, 100 les processus ne peuvent atteindre que 10qps Cette capacité de traitement est trop faible.

Existe-t-il une technique capable de gérer toutes les concurrences IO au sein d'un processus ? La réponse est oui, il s’agit de la technologie de réutilisation IO.

IORéutilisation/Boucle d'événement /Non bloquant asynchrone

En faitIORéutiliser l'historique Aussi longtemps en tant que multi-processus, Linux est fourni depuis longtemps sélectionnez L'appel système peut maintenir des connexions 1024 au sein d'un processus. Plus tard, l'appel système poll a été ajouté et certaines améliorations ont été apportées à poll. Résolu le problème de la limite 1024 et peut maintenir n'importe quel nombre de connexions. Mais select/poll Un autre problème est qu'il doit boucler pour détecter s'il y a des événements sur la connexion. Voici le problème, si le serveur a 100 millions de connexions, et qu'une seule connexion envoie des données au serveur à un certain moment, select/polldoit boucler 100 dix mille fois, dont seulement 1 fois sont des succès, et les 9910 000 9999 fois sont invalides, ce qui gaspille les ressources CPU .

Jusqu'àLinux 2.6 le noyau fournit un nouveau epollSystème L'appel peut maintenir un nombre illimité de connexions sans interrogation, ce qui résout véritablement le problème C10K . De nos jours, divers programmes de serveur IO asynchrones à haute concurrence sont basés sur epoll Implémentés, tels que Nginx, Node.js, Erlang, Golang. Un programme à processus unique et à thread unique comme Node.js peut gérer plus de 1 Des millionsTCP connexions, tout cela grâce à la technologie epoll.

IORéutilisez les programmes asynchrones non bloquants en utilisant le classique Reactor Modèle, RéacteurComme son nom l'indique, cela signifie réacteur, il ne traite aucune donnée envoyée et reçue lui-même. Il ne peut surveiller que les changements d'événements d'un socket handle.

RéacteurOui4 opérations principales :

  1. ajouterAjouter une priseécouter réacteur, peut être écouter socket peut également créer le clientsocket, ou un tube, eventfd , signaux, etc.

  2. setModifier l'écoute d'événement, vous pouvez définir le type d'écoute, tel que lisible, inscriptible. Lisible et facile à comprendre, pour écouter socket signifie que lorsqu'une nouvelle connexion client arrive, elle doit accepter. Pour que les connexions client reçoivent des données, recv est requis. Les événements inscriptibles sont un peu plus difficiles à comprendre. Un SOCKET possède une zone de cache. Si vous souhaitez vous connecter au client, envoyez 2M ne peuvent pas être envoyées en une seule fois. Par défaut, la zone de cache TCP du système d'exploitation n'a que . 256K. Vous ne pouvez envoyer 256K qu'une fois le cache plein, envoyer<.> Renverra l'erreur EAGAIN. À ce stade, vous devez surveiller les événements inscriptibles. En programmation asynchrone pure, vous devez surveiller les événements inscriptibles pour vous assurer que l'opération envoyer est totalement non bloquante. .

  3. del

    du réacteurSupprimé de, ne plus écouter les événements

  4. rappel est la logique de traitement correspondante après que l'événement se produit, généralement dans ajouter/définir est formulé. Le langage C est implémenté avec des pointeurs de fonctions, JS peut utiliser des fonctions anonymes, PHPVous pouvez utiliser des fonctions anonymes, des tableaux de méthodes d'objet et des noms de fonctions de chaîne.


Reactor n'est qu'un générateur d'événements, en fait socket gère les opérations, telles que se connecter/accepter, envoyer/recv, fermer est en rappel Terminé en . Pour un codage spécifique, veuillez vous référer au pseudocode suivant :

RéacteurLe modèle peut également être utilisé avec multi-processus, la combinaison de plusieurs threads peut non seulement obtenir un IO asynchrone non bloquant, mais également profiter de plusieurs cœurs. Les programmes de serveur asynchrone populaires actuels sont tous de cette manière : tels que

  • Nginx : multi-processus Reactor

  • Nginx+Lua : Multi-processusRéacteur+Coroutine

  • Golang : Single ThreadReactor+Coroutine multi-thread

  • Swoole: Multi-threadReactor+Multi- processusWorker

Qu'est-ce que la coroutine

La coroutine du point de vue du sous-jacent La technologie En fait, il s'agit toujours d'un modèle IO Reactor asynchrone.La couche d'application implémente elle-même la planification des tâches et utilise Reactor pour changer chaque thread en mode utilisateur en cours d'exécution, mais l'existence de Reactor est complètement invisible dans le code utilisateur.


Pratique de programmation d'E/S simultanées PHP

PHPExtensions associées

  • Stream : PHP fourni par le noyau socketPackage

  • Sockets : au sous-jacent Prise API wrapper

  • Libevent : pour libeventEncapsulation de bibliothèque

  • Événement : basé sur LibeventEncapsulation plus avancée, prenant en charge les interfaces orientées objet, les minuteries et le traitement du signal

  • Pcntl/Posix : Prise en charge de plusieurs processus, signaux et gestion de processus

  • Pthread : multi-threading, gestion des threads, support des verrous

  • PHPIl existe également des extensions associées pour la mémoire partagée, les sémaphores et les files d'attente de messages

  • PECL : Bibliothèque d'extensions pour PHP, y compris Il couvre la couche inférieure du système, l'analyse des données, les algorithmes, les pilotes, le calcul scientifique, les graphiques, etc. S'il n'est pas trouvé dans la bibliothèque standard PHP, vous pouvez trouver ce que vous voulez dans PECL fonction.

PHPAvantages et inconvénients du langage

Avantages de PHP :

  1. Le premier est la simplicité, PHP C'est plus simple que n'importe quel autre langage. Si vous voulez vous lancer, PHPVous pouvez vraiment vous lancer. une semaine. C++Il existe un livre intitulé "21Days of Deep LearningC++》, en fait, 21 est impossible à apprendre en un jour, il on peut même dire que le C++Il est impossible de le maîtriser en profondeur sans 3-5 ans. Mais PHP peut certainement 7 Tianmen. Ainsi PHPLe nombre de programmeurs est très important et le recrutement est plus facile que les autres langages.

  2. PHP est très puissant car PHP L'officiel la bibliothèque standard et la bibliothèque d'extensions fournissent 99 % des éléments pouvant être utilisés pour la programmation du serveur. La bibliothèque d'extensions PHP PECL fournit toutes les fonctionnalités que vous souhaitez.

AussiPHPIl y en a plus de 20 ans d'histoire, l'écosystème est très vaste, et vous pouvez trouver beaucoup de code sur Github.

Inconvénients de PHP :

  1. Les performances sont relativement médiocres, car il s'agit après tout d'un script dynamique et ne convient pas aux calculs intensifs si le même programme PHP est utilisé . C/C++ est écrit en , la version PHP est pire que cent fois.

  2. Tout le monde sait que la convention de dénomination des fonctions est médiocre, PHP Ça rapporte plus attention à l'aspect pratique et n'a pas de réglementation. La dénomination de certaines fonctions est très déroutante, il faut donc se rendre au manuel de PHP à chaque fois.

  3. La granularité de l'interface des structures de données et des fonctions fournies par est relativement grossière. PHP n'a qu'une seule structure de données Array, la couche sous-jacente est basée sur Table de hachage. Tableaude PHP assemblé Carte, Ensemble, Vecteur , File d'attente, Pile, Fonctions de structures de données telles que Heap. De plus, PHP dispose d'un SPL

    qui fournit une encapsulation de classe d'autres données structures.

Donc PHP

  1. PHP

    est plus adapté aux applications pratiques, un outil de développement commercial et de mise en œuvre rapide
  2. PHP

    ne convient pas Développer des logiciels sous-jacents
  3. en utilisant C/C++, JAVA, Golang et d'autres langages compilés statiques servent de complément à PHP

    , combinant dynamique et statique
  4. Utilisez l'outil IDE

    pour obtenir la complétion automatique et les invites de grammaire


L'extension

Swoole de PHP

est basée sur l'extension ci-dessus en utilisant du PHP pur Vous pouvez entièrement implémenter des programmes serveur et client réseau asynchrones. Cependant, si vous souhaitez implémenter un thread similaire à plusieurs threads IO, il reste encore beaucoup de travail de programmation fastidieux à faire, notamment sur la façon de gérer les connexions. et comment assurer l'envoi et la réception des données, Atomicité, traitement des protocoles réseau. De plus, PHPLes performances du code dans la partie traitement du protocole sont relativement médiocres, j'ai donc démarré un nouveau projet open source Swoole , utilisant le langage C et PHPLe combiné a fait le travail. Les modules métier flexibles et modifiables utilisent PHP pour une efficacité de développement élevée, et les parties de base sous-jacentes et de traitement du protocole utilisent CLa mise en œuvre du langage garantit des performances élevées. Il est chargé en PHP de manière étendue, fournissant un cadre de communication réseau complet, puis en PHP code pour écrire des affaires. Son modèle est basé sur le multi-threadingReactor+multi-processusWorker, qui prend en charge à la fois entièrement asynchrone, prend également en charge semi-asynchrone et semi-synchrone. Quelques fonctionnalités de

Swoole :

  • Accepter fil de discussion, résolvant Accepter goulot d'étranglement des performances et problème de groupe tonitruant

  • MultipleIOLes threads peuvent mieux utiliser les multicœurs

  • Fournir des modes entièrement asynchrones et semi-synchrones et semi-asynchrones2

  • Utilisez le mode asynchrone pour gérer une concurrence élevéeIO

  • Utilisez-le pour une partie de logique métier complexe Mode synchrone

  • La couche inférieure prend en charge la traversée de toutes les connexions, l'envoi de données entre elles, la fusion et la division automatiques des paquets de données et l'envoi atomique de données.

Processus de SwooleProcessus de /Modèle de filetage :

SwooleFlux d'exécution du programme :

Utilisez l'extension PHP+Swoole pour implémenter la programmation de communication asynchrone

L'exemple de code se trouve sur https://github.com/swoole/swoole-src Vérification de la page d'accueil.

TCPServeur et Client

AsynchroneTCPServeur :

Icinouveau swoole_server objet, puis Les paramètres sont transmis au HOST et au PORT surveillés, puis 3 fonctions de rappel, à savoir onConnect lorsqu'une nouvelle connexion arrive, onReceiveDonnées reçues d'un certain client, onCloseUn certain client est fermé, connexion . Enfin, appelez start pour démarrer le programme serveur. swooleLa couche inférieure commencera à correspondre en fonction du nombre de CPU cœurs la machine actuelle a un nombre de threads Reactor et de processus Worker.

Client asynchrone :

L'utilisation du client est similaire à celle du serveur sauf que il y a des événements de rappel4, onConnect connecté avec succès au serveur, puis vous pouvez envoyer des données au serveur. onErrorÉchec de la connexion au serveur. onReceiveLe serveur a envoyé des données à la connexion client. onCloseLa connexion est fermée.

Après avoir défini le rappel d'événement, lancez la connectez-vous au serveur, les paramètres sont ceux du serveur IP, PORT et délai d'attente.

Client de synchronisation :

Synchroniser le le client n'a pas besoin de définir de rappels d'événements. Il n'a pas d'écoute Reactor et bloque en série. Attendez la fin de IO avant de passer à l'étape suivante.

Tâches asynchrones :

La fonction de tâche asynchrone permet d'exécuter une fonction chronophage ou bloquante dans un programme Serveur purement asynchrone. L'implémentation sous-jacente utilise un pool de processus. Une fois la tâche terminée, onFinish sera déclenché et les résultats du traitement de la tâche pourront être obtenus dans le programme. Par exemple, un IM doit être diffusé. S'il est diffusé directement en code asynchrone, cela peut affecter le traitement d'autres événements. De plus, la lecture et l'écriture de fichiers peuvent également être implémentées à l'aide de tâches asynchrones, car les descripteurs de fichiers ne peuvent pas être utilisés comme socket comme RéacteurSurveillance. Étant donné que le descripteur de fichier est toujours lisible, la lecture directe du fichier peut bloquer le programme serveur. L'utilisation de tâches asynchrones est un très bon choix.

Minuteur asynchrone en millisecondes

Ceci 2 interfaces implémentent des JSsetInterval , setTimeout la fonction peut être définie dans n Implémenter un fonction par intervalles de millisecondes ou exécuter une fonction après n millisecondes.

AsynchroneMySQLClient

swoole fournit également un pool de connexions intégré MySQL client asynchrone, qui peut définir le nombre maximum de connexions MySQL. Les requêtes SQL simultanées peuvent réutiliser ces connexions au lieu de les créer à plusieurs reprises, ce qui protège MySQLÉvitez que les ressources de connexion ne soient épuisées.

AsynchroneRedisClient

AsynchroneWeb Programme

La logique du programme vient de Redis, puis affichez la page HTML. En utilisant ab les performances de mesure de pression sont les suivantes :

Le la même logique est dans Les résultats des tests de performances sous php-fpm sont les suivants :

WebSocketProgramme

swoole possède un serveur websocket intégré, qui peut être implémenté en fonction sur ce Web La fonction de push de page active, telle que WebIM. Il existe un projet open source qui peut être utilisé comme référence. https://github.com/matyhtf/php-webim

PHP+SwooleCoroutines

La programmation asynchrone utilise généralement des rappels. Si vous rencontrez une logique très complexe, les fonctions de rappel peuvent être imbriquées couche par couche. Les coroutines peuvent résoudre ce problème. Le code peut être écrit de manière séquentielle, mais le runtime est asynchrone et non bloquant. Les ingénieurs de Tencent basés sur l'extension Swoole et PHP5.5 La syntaxe Yield/Generator implémente une coroutine similaire à Golang, le nom du projet est TSF(Tencent Server Framework), adresse du projet open source : https://github.com/tencent-php/tsf. Actuellement dans les entreprises de Tencent QQ, QQ projets et roues de compte public Éléments ignorés pour contrôler les infractions au code de la route ont été appliqués à grande échelle .

TSF est également très simple à utiliser Les appels suivants 3Les opérations IO sont entièrement sérialisées. Mais il est en réalité exécuté de manière asynchrone et non bloquante. TSFLe planificateur sous-jacent prend en charge l'exécution du programme, dans le IO Une fois terminé, l'exécution se poursuivra vers le bas.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal