Heim  >  Artikel  >  Backend-Entwicklung  >  Warum benötigt PHP asynchrone Programmierung? Detaillierte Erklärung der asynchronen PHP-Programmierung (mit Beispielen)

Warum benötigt PHP asynchrone Programmierung? Detaillierte Erklärung der asynchronen PHP-Programmierung (mit Beispielen)

不言
不言nach vorne
2019-01-23 10:11:043226Durchsuche

Der Inhalt dieses Artikels handelt davon, warum PHP asynchrone Programmierung benötigt? Die ausführliche Erklärung der asynchronen PHP-Programmierung (mit Beispielen) hat einen gewissen Referenzwert. Ich hoffe, dass sie für Sie hilfreich ist.

Mein Wissen über PHP asynchron ist immer noch ziemlich verwirrend. Ich schreibe diesen Artikel, um das Problem zu klären.

Traditionelles PHP-FPM Wenn ein Prozess eine Anforderung ausführt, wie viele Prozesse müssen generiert werden, um die gleiche Parallelität zu erreichen? Was noch schlimmer ist, ist, dass jede Anfrage neu kompiliert und ausgeführt werden muss, was dazu führt, dass die Parallelität nie zunimmt. Daher die Entstehung von Swoole und WorkerMan sind zwei beliebte Resident-Memory-Frameworks in China [1]. Die Prinzipien dieser beiden Frameworks bestehen darin, Ereignisschleifen zu verwenden, um das Programm im Speicher zu halten, auf externe Anforderungen zu warten und eine hohe Parallelität zu erreichen.

Warum Asynchronität benötigt wird

Schauen wir uns zunächst ein Beispiel an

Erstellen Sie eine neue Datei slowServer.php im Arbeitsverzeichnis

<?php
sleep(5); // 5秒后才能返回请求
echo &#39;done&#39;;

Starten Sie den Dienst

$ php -S localhost:8081 slowServer.php

Öffnen Sie ein anderes Terminal und installieren Sie Abhängigkeiten

$ pecl install event # 安装 event 扩展
$ composer require workerman/workerman
$ composer require react/http-client:^0.5.9

Erstellen Sie eine neue Datei 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();

Öffnen Sie den Server

php worker.php start

Öffnen zwei Registerkarten im Browser. Beide öffnen die URL http://localhost:8082. Zu diesem Zeitpunkt können Sie sehen, dass das Terminal „1“ ausgibt und nach einer Weile erneut „1“ ausgibt. Der Grund dafür ist, dass der 8081-Server bei der Verarbeitung der ersten Anfrage blockiert ist Wenn die Anfrage abgeschlossen ist, beginnt die Verarbeitung der zweiten Anfrage. Das heißt, wie viele Prozesse müssen nacheinander ausgeführt werden, um die gleiche Anzahl von Parallelitäten zu erreichen, genau wie bei PHP-FPM. Ändern Sie nun den 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();
};

Öffnen Sie nun den Dienst und initiieren Sie eine Anfrage im Browser. Es wird festgestellt, dass die zweite „1“ unmittelbar nach der Anfrage ausgegeben wird, die erste Anfrage jedoch noch nicht beendet ist. Dies zeigt an, dass der Prozess nicht mehr blockiert ist und das Ausmaß der Parallelität von der CPU und dem Speicher abhängt, nicht von der Anzahl der Prozesse.

Warum Asynchronität erforderlich ist

Aus dem obigen Beispiel geht hervor, dass das Reactphp-Framework die HTTP-Anfrage asynchron macht und die CPU-Funktion nicht blockiert um die nächste Anfrage zu bearbeiten. Das heißt, die CPU-Schleife wartet auf die Rückkehr von 8081 und verwandelt sich in eine Epoll-Warteschleife.

Die Bedeutung von asynchron besteht darin, die CPU von IO-Wartezeiten zu befreien und andere Rechenaufgaben erledigen zu können. Wenn Sie wissen möchten, wie Sie das Framework verwenden, um eine asynchrone Implementierung zu erreichen, lesen Sie einfach hier. WorkerMan kann in Kombination mit ReactPHP oder seiner eigenen AsyncTcpConnection bereits die asynchronen Anforderungen vieler IO-Anfragen erfüllen. Lassen Sie uns weiter diskutieren, wie diese Frameworks asynchron sind.

Welche Orte sollten asynchron gemacht werden?

Durch das obige Beispiel wissen wir bereits, dass die CPU nicht einmal für die Ausführung benötigt wird, sondern beim Warten auf io das io Der Prozess sollte asynchron erfolgen.

Ereignisschleife implementieren

Das obige Beispiel verwendet Reactphp, um die HTTP-Anfrage in eine asynchrone umzuwandeln. Tatsächlich ist das WorkerMan-Framework selbst auch asynchron So funktioniert WorkerMan: Aktivieren Sie die Funktion onMessage, um Anfragen asynchron anzunehmen. Erstellen Sie zunächst die folgende Datei „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(); // 开始循环

Ausführung starten

$ php react.php

In einem anderen Terminal ausführen

telnet 127.0.0.1 8081

Sie sehen die erste Terminalausgabe „1“.

Ich habe vor „PHP verwendet Epoll“ einen Artikel geschrieben, der die Grundlage dieses Artikels bildet. In diesem Artikel wird der Ereignisrückruf durch Timing implementiert, d. h.

$event->add($seconds);

Hier wird der Ereignisrückruf durch Erkennen, ob fd geschrieben wurde, implementiert. Wenn Inhalte in fd geschrieben werden, wird die Funktion „react“ aufgerufen und die CPU wird verwendet. Wenn der Prozess zu diesem Zeitpunkt eine weitere asynchrone Anfrage ausführt, z. B. das Anfordern einer Webseite mithilfe des Reactphp-Frameworks, gibt das Programm die CPU frei. Wenn zu diesem Zeitpunkt eine weitere Anfrage eingeht, kann es zurückrufen, um eine weitere „Reaktions“-Funktion auszuführen . Dies erhöht den Grad der Parallelität.

Coroutine

Generator

Dies ist die offizielle PHP-Dokumentation für den Generator 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";
}
Der Generator speichert den Status jedes Mal, wenn das Programm ausgeführt wird, um nachzugeben, und gibt dann $i zurück. Ob die Ausführung der Schleife in gen_one_to_ three fortgesetzt werden soll, hängt vom Hauptprogramm ab Ob weiter aufgerufen werden soll

Was ist eine Coroutine?

Eine andere Möglichkeit, das obige Programm zu schreiben, ist

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

while ($value = gen_one_to_three()) {
    echo "$value\n";
}
Es ist ersichtlich, dass es sich um eine Coroutine handelt Eine Art Funktion ist so gekapselt, dass sie zu einer Funktion wird, die unterbrochen werden kann und sich eher wie ein Unterprozess oder Unterthread als wie eine Funktion verhält. Auf die spezifische Schreibmethode von Coroutine wird hier nicht näher eingegangen, da die Schreibmethode von Coroutine sehr kompliziert ist und möglicherweise eine weitere Kapselungsschicht erfordert, um einfach zu verwenden zu sein.

Coroutine und asynchron

Da die Coroutine unterbrochen werden kann, solange die Ereignisschleife initiiert wird, nachdem das Programm die Anforderung initiiert hat, kehrt sie mit Ertrag zurück und Anschließend führt das Programm weiterhin den Hauptteil aus. Warten Sie im Programmteil, bis das Ereignis zurückkehrt, lösen Sie die Funktion aus und führen Sie Generatot::next() oder Generator::send() aus, um mit der Ausführung des Coroutine-Teils fortzufahren. Nach der Kapselung ist es so, als gäbe es keine asynchrone Rückruffunktion, die einer synchronen Funktion sehr ähnlich ist.

Es gibt jetzt zwei Frameworks, ampphp und swoole, die Coroutinen kapseln. Wenn Sie interessiert sind, können Sie mehr darüber erfahren.

Das obige ist der detaillierte Inhalt vonWarum benötigt PHP asynchrone Programmierung? Detaillierte Erklärung der asynchronen PHP-Programmierung (mit Beispielen). Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:segmentfault.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen