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 'done';
Démarrez le service
$ php -S localhost:8081 slowServer.php
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
Créez un nouveau fichier worker.php
require_once __DIR__ . '/vendor/autoload.php'; 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();
Démarrez le serveur
php worker.php start
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(); };
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('tcp://0.0.0.0:8081', $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, 'react', $socket); // 注册一个事件,检测 fd 有没有写入内容 $event->add(); $eventBase->loop(); // 开始循环
Démarrer l'exécution
$ php react.php
Exécuter dans un autre terminal
telnet 127.0.0.1 8081
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);
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"; }
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"; }
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!