Pourquoi PHP a-t-il besoin d'une programmation asynchrone ? Explication détaillée de la programmation asynchrone PHP (avec exemples)

不言
Libérer: 2023-04-04 20:34:02
avant
3231 Les gens l'ont consulté

Le contenu de cet article explique pourquoi PHP a besoin d'une programmation asynchrone ? L'explication détaillée de la programmation asynchrone PHP (avec exemples) a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer, j'espère qu'elle vous sera utile.

Mes connaissances sur PHP asynchrone sont encore assez confuses. J'écris cet article pour faire le tri. Il peut y avoir des erreurs.

php-fpm traditionnel Lorsqu'un processus exécute une requête, combien de processus doivent être générés pour obtenir la même simultanéité. Ce qui est pire, c'est que chaque requête doit être recompilée et exécutée, ce qui empêche la concurrence d'augmenter. D'où l'émergence de Swoole et WorkerMan sont deux frameworks de mémoire résidente populaires en Chine [1]. Les principes de ces deux frameworks sont d'utiliser des boucles d'événements pour garder le programme en mémoire, en attente de requêtes externes et atteindre une concurrence élevée.

Pourquoi l'asynchrone est nécessaire

Regardons d'abord un exemple

Créez un nouveau fichier slowServer.php dans le répertoire de travail

<?php
sleep(5); // 5秒后才能返回请求
echo &#39;done&#39;;
Copier après la connexion

Démarrez le service

$ php -S localhost:8081 slowServer.php
Copier après la connexion

Ouvrez un autre terminal et installez les dépendances

$ pecl install event # 安装 event 扩展
$ composer require workerman/workerman
$ composer require react/http-client:^0.5.9
Copier après la connexion

Créez un nouveau fichier worker.php

require_once __DIR__ . &#39;/vendor/autoload.php&#39;;
use Workerman\Worker;
use Workerman\Connection\AsyncTcpConnection;
use Amp\Artax\Response;

$http_worker = new Worker("http://0.0.0.0:8082");

$http_worker->count = 1; // 只开一个进程

$http_worker->onMessage = function($connection, $host) {
    echo 1;
    $data = file_get_contents('http://localhost:8081');
    $connection->send($data);
};

Worker::runAll();
Copier après la connexion

Démarrez le serveur

php worker.php start
Copier après la connexion

Ouvrez deux onglets dans le navigateur et ouvrez l'URL http://localhost:8082. À ce stade, vous pouvez voir que le terminal affiche "1", et après un certain temps, il affiche à nouveau "1". La raison en est que le serveur 8081 est bloqué en attendant le retour 8081 lors du traitement de la première requête. La demande est terminée, elle commencera à traiter la deuxième demande. C'est-à-dire que les requêtes sont exécutées une par une. Combien de processus doivent être établis pour atteindre le même nombre de simultanéités, tout comme php-fpm. Modifiez maintenant le code

$http_worker->onMessage = function($connection, $host) {
    echo 1;
    $loop    = Worker::getEventLoop();
    $client  = new \React\HttpClient\Client($loop);
    $request = $client->request('GET', 'http://localhost:8081');
    $request->on('error', function(Exception $e) use ($connection) {
        $connection->send($e);
    });
    $request->on('response', function ($response) use ($connection) {
        $response->on('data', function ($data) use ($connection) {
            $connection->send($data);
        });
    });
    $request->end();
};
Copier après la connexion

Ouvrez maintenant le service et lancez une requête dans le navigateur. On constate que le deuxième "1" est affiché immédiatement après la requête, mais la première requête n'est pas encore terminée. Cela indique que le processus n'est plus bloqué et que le degré de concurrence dépend du processeur et de la mémoire, et non du nombre de processus.

Pourquoi l'asynchrone est nécessaire

Cela ressort clairement de l'exemple ci-dessus. Le framework Reactphp rend la requête http asynchrone et rend la fonction onMessage non bloquante. pour traiter la prochaine demande. Autrement dit, la boucle CPU attend le retour de 8081, se transformant en attente epoll.

La signification de l'asynchrone est de libérer le CPU de l'attente d'E/S et de pouvoir gérer d'autres tâches informatiques. Si vous voulez savoir comment utiliser le framework pour réaliser une implémentation asynchrone, lisez simplement ici. WorkerMan, combiné à ReactPHP ou à son propre AsyncTcpConnection, peut déjà répondre aux besoins asynchrones de nombreuses requêtes io. Continuons à discuter de la manière dont ces frameworks sont asynchrones.

Quels endroits doivent être rendus asynchrones

Grâce à l'exemple ci-dessus, nous savons déjà qu'une fois que le CPU n'est pas requis pour l'exécution, mais en attendant io, l'io le processus doit être rendu asynchrone.

Implémentation d'une boucle d'événements

L'exemple ci-dessus utilise Reactphp pour transformer la requête http en asynchrone. En fait, le framework WorkerMan lui-même est également asynchrone. comment fonctionne WorkerMan Activez la fonction onMessage pour accepter les demandes de manière asynchrone. Créez d'abord le fichier suivant React.php

<?php
$context = stream_context_create();
$socket = stream_socket_server(&#39;tcp://0.0.0.0:8081&#39;, $errno, $errmsg, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN,$context); // 注册一个 fd(file descriptor)

function react($socket){
    $new_socket = stream_socket_accept($socket, 0, $remote_address);
    echo 1;
}

$eventBase = new EventBase();
$event = new Event($eventBase, $socket, Event::READ | Event::PERSIST, &#39;react&#39;, $socket); // 注册一个事件,检测 fd 有没有写入内容
$event->add();
$eventBase->loop(); // 开始循环
Copier après la connexion

Démarrer l'exécution

$ php react.php
Copier après la connexion

Exécuter dans un autre terminal

telnet 127.0.0.1 8081
Copier après la connexion

Vous verrez les sorties du terminal A '1 '.

J'ai écrit un article avant "php utilise epoll", qui est la base de cet article. Dans cet article, le rappel d'événement est implémenté via le timing, c'est-à-dire

$event->add($seconds);
Copier après la connexion

Ici, le rappel d'événement est implémenté en détectant si fd a écrit du contenu. Ce processus ne nécessite pas l'implication du CPU. . Lorsque fd contient du contenu, la fonction « react » sera appelée et le processeur commencera à être utilisé. Si le processus exécute une autre requête asynchrone à ce moment-là, comme demander une page Web à l'aide du framework Reactphp, le programme libérera le CPU. À ce moment-là, si une autre requête arrive, il pourra rappeler pour exécuter une autre fonction « réagir ». . Cela augmente le degré de concurrence.

Coroutine

Générateur

Ceci est la documentation PHP officielle pour le générateur http:// php. net/manual/zh/lang...

<?php
function gen_one_to_three() {
    for ($i = 1; $i <= 3; $i++) {
        //注意变量$i的值在不同的yield之间是保持传递的。
        yield $i;
    }
}

$generator = gen_one_to_three();
foreach ($generator as $value) {
    echo "$value\n";
}
Copier après la connexion
Le générateur enregistre l'état à chaque fois que le programme est exécuté pour produire, puis renvoie $i La poursuite de l'exécution de la boucle dans gen_one_to_two dépend de si. le programme principal continue d'appeler

Qu'est-ce qu'une coroutine ?

Une autre façon d'écrire le programme ci-dessus est

<?php
$i = 1;
function gen_one_to_three() {
    global $i;
    if ($i<=3){
        return $i++;
    }
}

while ($value = gen_one_to_three()) {
    echo "$value\n";
}
Copier après la connexion
On peut le voir cette coroutine C'est une sorte d'encapsulation d'une fonction, la transformant en une fonction qui peut être interrompue et se comporte plus comme un sous-processus ou un sous-thread que comme une fonction. La méthode d'écriture spécifique de la coroutine ne sera pas détaillée ici, car la méthode d'écriture de la coroutine est très compliquée et peut nécessiter une autre couche d'encapsulation pour être facile à utiliser.

Coroutine et asynchrone

Puisque la coroutine peut être interrompue, alors tant que la boucle d'événements est initiée après que le programme a lancé la requête, elle revient avec rendement, et puis le programme continue d'exécuter la partie principale du programme, attendez le retour de l'événement, déclenchez la fonction et exécutez Generatot::next() ou Generator::send() pour continuer l'exécution de la partie coroutine. Après encapsulation, c'est comme s'il n'y avait pas de fonction de rappel asynchrone, ce qui est très similaire à une fonction synchrone.

Il existe désormais deux frameworks, ampphp et swoole, qui encapsulent les coroutines. Si vous êtes intéressé, vous pouvez en apprendre davantage.

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:segmentfault.com
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