PHP asynchrone. Pourquoi?

image

La programmation asynchrone est aujourd'hui très demandée, en particulier dans le développement Web, où la réactivité des applications est particulièrement importante. Personne ne veut attendre que l'application «s'affaisse», même si à ce moment-là elle exécute une requête dans la base de données, envoie un e-mail ou travaille sur d'autres tâches qui peuvent prendre beaucoup de temps. Le client veut une réponse à son action, le meilleur de tous - tout de suite. Si votre application est lente, vous perdez des clients. Face à une application en vol stationnaire, le plus souvent l'utilisateur la ferme simplement et ne revient jamais. Du point de vue de l'utilisateur, l'application vient de se bloquer, il ne peut pas comprendre pourquoi cela s'est produit: effectue-t-il une opération complexe ou a-t-il cessé de fonctionner en principe.

Présentation de la traduction d'un article du développeur back-end de Skyeng, Sergey Zhuk.

Réactivité des applications


Les applications modernes sont souvent réactives, mais certaines tâches ou opérations, telles que l'échange de données sur un réseau, les E / S de fichiers ou l'interrogation d'une base de données, peuvent prendre du temps et ralentir considérablement l'application. Pour empêcher de telles opérations de bloquer l'application, vous pouvez les exécuter en arrière-plan, masquant ainsi le retard qu'elles provoquent. Dans le même temps, l'application reste sensible car elle peut continuer à effectuer d'autres tâches, par exemple, renvoyer le flux de contrôle à l'interface utilisateur ou répondre à d'autres événements.

Concurrence et asynchronie


Lorsque les gens voient du code asynchrone, le plus souvent, ils pensent immédiatement: "Génial, je peux paralléliser les processus!". Je peux vous décevoir, mais en fait ce n'est pas le cas. L'asynchronie et la concurrence ne sont pas la même chose. Il peut être difficile de saisir cette différence, alors essayons de le comprendre.

Si les tâches sont exécutées de manière asynchrone, elles ne se bloquent pas et l'exécution d'une tâche ne dépend pas de l'achèvement d'une autre. La concurrence, à son tour, implique le lancement de plusieurs tâches distinctes simultanément en tant qu'unités de travail indépendantes.

Asynchronie:
Allez terminer la tâche vous-même . Faites-moi savoir quand vous avez terminé et montrez-moi le résultat. En ce moment, je peux continuer à faire mon travail.

Le code asynchrone nécessite le traitement des dépendances qui surviennent lors de l'exécution des tâches, et cela est implémenté à l'aide de rappels. Lorsqu'une tâche est terminée, le code notifie une autre tâche. Le code asynchrone concerne essentiellement le temps nécessaire à la tâche (ordre des événements).
image
Accès simultané:
Embauchez autant de travailleurs que vous le souhaitez et partagez la tâche entre eux pour la terminer plus rapidement et prévenez-moi lorsque vous avez terminé. Je peux continuer à faire d'autres choses ou, si la tâche est urgente, je vais rester et attendre que vous reveniez avec les résultats. Ensuite, je peux composer le résultat final de tous les employés. L'exécution parallèle nécessite souvent plus de ressources, donc ici cela dépend essentiellement du matériel.

image
Pour comprendre la différence entre une exécution asynchrone et parallèle en utilisant un exemple réel, nous comparons deux serveurs Web populaires: Apache et Nginx. Ils illustrent parfaitement cette différence. Nginx utilise un modèle asynchrone basé sur les événements tandis qu'Apache utilise des threads parallèles. Apache crée de nouveaux threads pour chaque connexion supplémentaire, donc ici le nombre maximum de connexions autorisées dépend de la quantité de mémoire disponible dans le système. Lorsque la limite de connexion est atteinte, Apache cesse de créer des connexions supplémentaires. Le facteur limitant lors de la configuration d'Apache est la mémoire (rappelez-vous que l'exécution parallèle dépend souvent du matériel). Si le thread s'arrête, le client attend une réponse jusqu'à ce que le thread soit libre et peut envoyer une réponse.

Nginx ne fonctionne pas comme Apache - il ne crée pas de nouveaux threads pour chaque demande entrante. Nginx a un flux de travail principal (ou plusieurs travailleurs, souvent pour un processeur il y a un flux de travail), qui est monothread. Ce travailleur peut traiter des milliers de connexions "simultanément" et le fait de manière asynchrone, dans un thread, et non en parallèle dans plusieurs threads.

Ainsi, «l'asynchronie» est la façon dont nous construisons le système, c'est une composition de processus indépendants les uns des autres. Par «exécution parallèle», on entend l'exécution de plusieurs processus en même temps, alors qu'ils peuvent être liés ou non. En exécution asynchrone, nous traitons plusieurs tâches à la fois et en exécution parallèle, nous démarrons plusieurs processus en même temps. Cela peut sembler être la même chose, mais ce n'est pas le cas. L'asynchronie décrit une structure, le parallélisme décrit une façon de le faire.

L'exécution asynchrone peut être comparée aux périphériques d'E / S de votre ordinateur (souris, clavier, écran). Ils sont tous gérés par le système d'exploitation, mais chacun d'eux est une partie indépendante du noyau. Ces processus sont asynchrones, ils peuvent être parallèles, mais ce n'est pas nécessaire. Ainsi, afin d'assurer la cohérence, vous devez créer un lien entre ces pièces indépendantes afin de les coordonner.

Et ce backend?


Vous pouvez dire que la réactivité n'est pas si importante sur le backend. Toutes ces choses asynchrones sympas avec JavaScript se produisent sur un freeend, et votre serveur répond simplement aux demandes, donc un freeend devrait être responsable de la réactivité de l'application, mais pas vous. Oui, c'est vrai, mais la tâche du serveur ne se limite pas aux réponses de l'API. Parfois, vous devez gérer des tâches complexes, par exemple, télécharger une vidéo. Dans ce cas, la réactivité n'est peut-être pas un facteur clé, mais son manque de ressources est gaspillé car l'application doit être inactive. Il peut attendre la fin des opérations du système de fichiers, des interactions réseau, des requêtes de base de données, etc. Souvent, ces opérations d'E / S sont très lentes par rapport aux calculs du processeur, par exemple lorsque nous convertissons des fichiers vidéo. Et tandis que nous enregistrons ou lisons lentement le fichier, le processeur est obligé de se mettre en veille au lieu de faire un travail utile. Comme nous l'avons déjà découvert, au lieu d'attendre, nous pouvons exécuter ces tâches en arrière-plan. Comment? Allez-y.

PHP asynchrone


En JavaScript, prêt à l'emploi, un support intégré et des solutions pour l'écriture de code asynchrone sont disponibles. Il existe également Node.js, qui vous permet d'écrire des applications serveur asynchrones. En JavaScript, nous pouvons utiliser la fonction setTimeout () pour illustrer un exemple de code asynchrone:
image

Lorsque nous exécuterons ce code, nous verrons ce qui suit:
image

La fonction setTimeout () envoie le code à la file d'attente et l'exécute à la fin de la pile d'appels actuelle. Cela signifie que nous interrompons le flux synchrone de code et retardons l'exécution. Le deuxième appel à console.log () est effectué avant l'appel à la file d'attente à l'intérieur de l'appel setTimeout ().

Et PHP? En PHP, nous n'avons pas d'outils adaptés adaptés pour écrire du code vraiment asynchrone. Il n'y a pas d'équivalent à setTimeout (), et nous ne pouvons pas simplement retarder ou mettre en file d'attente n'importe quel code. C'est pourquoi des frameworks et des bibliothèques comme Amp et ReactPHP ont commencé à apparaître. Leur idée est de masquer les détails du langage de bas niveau et de donner à l'utilisateur des outils de haut niveau qui vous permettent d'écrire du code asynchrone et de contrôler l'exécution compétitive de processus comme JavaScript et Node.js.

Pourquoi devrais-je utiliser PHP s'il y a Node.js et Go?


Cette question se pose souvent quand il s'agit de PHP asynchrone. Pour une raison quelconque, beaucoup sont contre l'utilisation de PHP pour écrire du code asynchrone. Quelqu'un suggère toujours d'utiliser Go ou Node.js. au lieu de PHP.

Le tweet assertchris décrit parfaitement ces situations:

image

Bien sûr, lorsque PHP venait juste d'être créé, il n'y avait aucun but d'en faire un langage de programmation pouvant être utilisé pour créer de grandes applications complexes. A cette époque, personne ne pensait à JavaScript ou à l'asynchronie. Mais maintenant, nous avons un PHP complètement différent qui a déjà ses propres fonctions pour écrire du code asynchrone (par exemple, la fonction stream_select ()).

Oui, vous pouvez utiliser Go ou Node.js pour créer des applications de serveur asynchrones, mais cela ne résout pas toujours le problème. Si vous avez déjà une vaste expérience de PHP, il vous sera beaucoup plus facile d'apprendre simplement les bibliothèques et les outils qui conviennent à votre situation que d'apprendre un nouveau langage et un nouvel écosystème. Des outils comme ReactPHP ou Amp vous permettent d'écrire du code asynchrone comme vous le faites dans Node.js. Ces outils sont assez développés et ont des versions stables, vous pouvez donc les utiliser en toute sécurité en production.

Pas seulement CLI


Je ne vais pas écrire un chat, un serveur ou quelque chose comme ça. Je veux juste accélérer le site.

Il est généralement admis que le code asynchrone ne peut être utilisé que dans les scripts CLI. Il est absolument normal d'intégrer certains composants asynchrones dans un environnement synchrone traditionnel, même dans une application Web traditionnelle. Par exemple, vous pouvez recevoir une demande, puis appeler plusieurs ressources différentes de manière asynchrone, et lorsque ces appels sont terminés, vous pouvez continuer le cycle de vie réponse-demande et, par conséquent, la page s'affiche plus rapidement.

Ou vous devez effectuer des appels API externes - par exemple, lorsqu'un utilisateur effectue un paiement, vous souhaitez envoyer un e-mail ou une notification push. Vous pouvez effectuer ces appels d'API de manière asynchrone, puis poursuivre votre flux de code synchrone traditionnel. Il n'est pas nécessaire de réécrire complètement l'application et de supprimer tout ce qui ralentit. Identifiez simplement les goulots d'étranglement qui interfèrent avec les performances, et il est possible qu'ils puissent être corrigés à l'aide de code asynchrone.

Oui, le code asynchrone est dans la plupart des cas toujours utilisé dans les scripts CLI, mais il n'est pas limité aux chats et serveurs en temps réel. Si vous voulez simplement accélérer votre site, vous n'avez pas besoin de renoncer à votre framework Symfony ou Laravel et de créer votre propre serveur d'applications complètement asynchrone.

Conclusion


N'ayez pas peur d'apprendre un nouveau paradigme. PHP est bien plus que «exécuter un script, exécuter du code et mourir». Vous serez surpris lorsque vous réaliserez que vous pouvez utiliser le PHP familier d'une manière complètement nouvelle, comme vous ne l'avez jamais utilisé! Le code asynchrone et la programmation orientée événement vous permettront de mieux comprendre PHP et les possibilités d'utilisation de ce langage. Vous n'avez pas besoin d'apprendre un nouveau langage pour écrire des applications asynchrones simplement parce que "PHP est un outil inapproprié" ou "J'ai toujours fait cela, il ne peut pas être amélioré." Essayez-le!

Eh bien, nous vous rappelons également que nous avons toujours beaucoup de postes vacants intéressants pour les développeurs!

Source: https://habr.com/ru/post/fr448968/


All Articles