Heim > Backend-Entwicklung > PHP-Tutorial > Detaillierte Erklärung der PHP-Coroutinen: Go + Chan + Defer

Detaillierte Erklärung der PHP-Coroutinen: Go + Chan + Defer

藏色散人
Freigeben: 2023-04-10 09:32:01
nach vorne
4198 Leute haben es durchsucht

Swoole4 bietet ein leistungsstarkes CSP-Coroutine-Programmiermodell für die PHP-Sprache. Die unterste Ebene bietet 3 Schlüsselwörter, mit denen verschiedene Funktionen problemlos implementiert werden können. Swoole4PHP语言提供了强大的CSP协程编程模式。底层提供了3个关键词,可以方便地实现各类功能。

  • Swoole4提供的PHP协程语法借鉴自Golang,在此向GO开发组致敬
  • PHP+Swoole协程可以与Golang很好地互补。Golang:静态语言,严谨强大性能好,PHP+Swoole:动态语言,灵活简单易用
本文基于Swoole-4.2.9PHP-7.2.9版本

关键词

  • go :创建一个协程
  • chan :创建一个通道
  • defer :延迟任务,在协程退出时执行,先进后出

3个功能底层实现全部为内存操作,没有任何IO资源消耗。就像PHPArray一样是非常廉价的。如果有需要就可以直接使用。这与socketfile操作不同,后者需要向操作系统申请端口和文件描述符,读写可能会产生阻塞的IO等待。

推荐学习:《PHP视频教程

协程并发

使用go函数可以让一个函数并发地去执行。在编程过程中,如果某一段逻辑可以并发执行,就可以将它放置到go协程中执行。

顺序执行

function test1() 
{
    sleep(1);
    echo "b";
}
    
function test2() 
{
    sleep(2);
    echo "c";
}

test1();
test2();
Nach dem Login kopieren

执行结果:

htf@LAPTOP-0K15EFQI:~$ time php b1.php
bc
real    0m3.080s
user    0m0.016s
sys     0m0.063s
htf@LAPTOP-0K15EFQI:~$
Nach dem Login kopieren

上述代码中,test1test2会顺序执行,需要3秒才能执行完成。

并发执行

使用go创建协程,可以让test1test2两个函数变成并发执行。

Swoole\Runtime::enableCoroutine();

go(function () 
{
    sleep(1);
    echo "b";
});
    
go(function () 
{
    sleep(2);
    echo "c";
});
Nach dem Login kopieren
SwooleRuntime::enableCoroutine()作用是将PHP提供的streamsleeppdomysqliredis等功能从同步阻塞切换为协程的异步IO

执行结果:

bchtf@LAPTOP-0K15EFQI:~$ time php co.php
bc
real    0m2.076s
user    0m0.000s
sys     0m0.078s
htf@LAPTOP-0K15EFQI:~$
Nach dem Login kopieren

可以看到这里只用了2秒就执行完成了。

  • 顺序执行耗时等于所有任务执行耗时的总和 :t1+t2+t3...
  • 并发执行耗时等于所有任务执行耗时的最大值 :max(t1, t2, t3, ...)

协程通信

有了go关键词之后,并发编程就简单多了。与此同时又带来了新问题,如果有2个协程并发执行,另外一个协程,需要依赖这两个协程的执行结果,如果解决此问题呢?

答案就是使用通道(Channel),在Swoole4协程中使用new chan就可以创建一个通道。通道可以理解为自带协程调度的队列。它有两个接口pushpop

  • push:向通道中写入内容,如果已满,它会进入等待状态,有空间时自动恢复
  • pop:从通道中读取内容,如果为空,它会进入等待状态,有数据时自动恢复

使用通道可以很方便地实现并发管理

$chan = new chan(2);

# 协程1
go (function () use ($chan) {
    $result = [];
    for ($i = 0; $i < 2; $i++)
    {
        $result += $chan->pop();
    }
    var_dump($result);
});

# 协程2
go(function () use ($chan) {
   $cli = new Swoole\Coroutine\Http\Client('www.qq.com', 80);
       $cli->set(['timeout' => 10]);
       $cli->setHeaders([
       'Host' => "www.qq.com",
       "User-Agent" => 'Chrome/49.0.2587.3',
       'Accept' => 'text/html,application/xhtml+xml,application/xml',
       'Accept-Encoding' => 'gzip',
   ]);
   $ret = $cli->get('/');
   // $cli->body 响应内容过大,这里用 Http 状态码作为测试
   $chan->push(['www.qq.com' => $cli->statusCode]);
});

# 协程3
go(function () use ($chan) {
   $cli = new Swoole\Coroutine\Http\Client('www.163.com', 80);
   $cli->set(['timeout' => 10]);
   $cli->setHeaders([
       'Host' => "www.163.com",
       "User-Agent" => 'Chrome/49.0.2587.3',
       'Accept' => 'text/html,application/xhtml+xml,application/xml',
       'Accept-Encoding' => 'gzip',
   ]);
   $ret = $cli->get('/');
   // $cli->body 响应内容过大,这里用 Http 状态码作为测试
   $chan->push(['www.163.com' => $cli->statusCode]);
});
Nach dem Login kopieren

执行结果:

htf@LAPTOP-0K15EFQI:~/swoole-src/examples/5.0$ time php co2.php
array(2) {
  ["www.qq.com"]=>
  int(302)
  ["www.163.com"]=>
  int(200)
}

real    0m0.268s
user    0m0.016s
sys     0m0.109s
htf@LAPTOP-0K15EFQI:~/swoole-src/examples/5.0$
Nach dem Login kopieren

这里使用go创建了3个协程,协程2和协程3分别请求qq.com163.com主页。协程1需要拿到Http请求的结果。这里使用了chan来实现并发管理。

  • 协程1循环两次对通道进行pop,因为队列为空,它会进入等待状态
  • 协程2和协程3执行完成后,会push数据,协程1拿到了结果,继续向下执行

延迟任务

在协程编程中,可能需要在协程退出时自动实行一些任务,做清理工作。类似于PHPregister_shutdown_function,在Swoole4中可以使用defer实现。

Swoole\Runtime::enableCoroutine();

go(function () {
    echo "a";
    defer(function () {
        echo "~a";
    });
    echo "b";
    defer(function () {
        echo "~b";
    });
    sleep(1);
    echo "c";
});
Nach dem Login kopieren

执行结果:

htf@LAPTOP-0K15EFQI:~/swoole-src/examples/5.0$ time php defer.php
abc~b~a
real    0m1.068s
user    0m0.016s
sys     0m0.047s
htf@LAPTOP-0K15EFQI:~/swoole-src/examples/5.0$
Nach dem Login kopieren

结语

Swoole4提供的Go + Chan + DeferPHP带来了一种全新的CSP并发编程模式。灵活使用Swoole4

  • Die Syntax der von Swoole4 bereitgestellten PHP-Coroutine ist von Golang entlehnt, hiermit beziehen wir uns auf GO Herzlichen Glückwunsch an das Entwicklungsteam
  • PHP+Swoole-Coroutinen können Golang sehr gut ergänzen. Golang: statische Sprache, streng, leistungsstark und gut in der Leistung, PHP+Swoole: dynamische Sprache, flexibel, einfach und benutzerfreundlich
Dieser Artikel basiert auf den Versionen Swoole-4.2.9 und PHP-7.2.9

Schlüsselwörter

  • go: Erstellen Sie eine Coroutine
  • chan: Erstellen Sie einen Kanal
  • defer: Aufgabe verzögern , ausgeführt, wenn die Coroutine beendet wird, zuerst rein, zuletzt raus
Die zugrunde liegende Implementierung dieser 3-Funktionen sind alle
Speicheroperationen🎜, ohne jegliche IO Code> Ressourcenverbrauch. Genau wie das <code>Array von PHP ist es sehr günstig. Sie können es bei Bedarf direkt verwenden. Dies unterscheidet sich von socket- und file-Vorgängen. Letztere müssen Ports und Dateideskriptoren vom Betriebssystem beantragen, und das Lesen und Schreiben kann zu einer Blockierung von IO warten. 🎜🎜Empfohlenes Lernen: „<a href="https://www.php.cn/course/list/29/type/2.html" target="_blank">PHP-Video-Tutorial</a>“<br>🎜<h1>Coroutine-Parallelität</h1>🎜Mit der Funktion <code>go kann eine Funktion gleichzeitig ausgeführt werden. Wenn während des Programmiervorgangs ein bestimmter Teil der Logik gleichzeitig ausgeführt werden kann, kann er zur Ausführung in die Coroutine go eingefügt werden. 🎜

Sequentielle Ausführung

rrreee

Ausführungsergebnis:

rrreee🎜Im obigen Code werden test1 und test2 nacheinander ausgeführt. Es sind 3 Sekunden erforderlich, um die Ausführung abzuschließen. 🎜

Gleichzeitige Ausführung

🎜Verwenden Sie go, um eine Coroutine zu erstellen, mit der die beiden Funktionen test1 und test2 gleichzeitig ausgeführt werden können . 🎜rrreee
SwooleRuntime::enableCoroutine() wird verwendet, um stream, sleep, pdo
, mysqli, redis und andere Funktionen wechseln von der synchronen Blockierung zur asynchronen Coroutine IO

Ausführungsergebnis:

rrreee 🎜Sie können sehen, dass die Ausführung nur 2 Sekunden dauerte. 🎜
  • Die sequentielle Ausführungszeit ist gleich der Summe der Ausführungszeit aller Aufgaben: t1+t2+t3...
  • Die gleichzeitige Ausführungszeit entspricht der Ausführung aller Aufgaben. Maximaler zeitaufwändiger Wert: max(t1, t2, t3, ...)

Coroutine-Kommunikation

🎜Mit go Nach dem Schlüsselwort wird die gleichzeitige Programmierung viel einfacher. Gleichzeitig bringt es neue Probleme mit sich, wenn 2 Coroutinen gleichzeitig ausgeführt werden und eine andere Coroutine auf die Ausführungsergebnisse dieser beiden Coroutinen angewiesen ist. 🎜🎜Die Antwort ist die Verwendung eines Kanals (Channel). Sie können einen Kanal erstellen, indem Sie new chan in der Swoole4-Coroutine verwenden. Ein Kanal kann als Warteschlange mit eigener Coroutine-Planung verstanden werden. Es verfügt über zwei Schnittstellen push und pop: 🎜
  • push: Inhalte in den Kanal schreiben, wenn dieser voll ist wechselt in den Wartezustand und stellt sich automatisch wieder her, wenn Platz vorhanden ist
  • pop: Liest den Inhalt aus dem Kanal. Wenn er leer ist, wechselt er in den Wartezustand und stellt sich automatisch wieder her, wenn Es gibt Daten
🎜Durch die Verwendung von Kanälen kann leicht ein 🎜Parallelitätsmanagement🎜 erreicht werden. 🎜rrreee

Ausführungsergebnis:

rrreee🎜Hier wurde go verwendet, um 3-Coroutinen, Coroutine 2 und Coroutine Process zu erstellen 3 fordert die Homepages von qq.com bzw. 163.com an. Coroutine 1 muss das Ergebnis der Http-Anfrage abrufen. chan wird hier verwendet, um das Parallelitätsmanagement zu implementieren. 🎜
  • Die Coroutine 1 durchläuft zwei Schleifen, um den Kanal zu pop. Da die Warteschlange leer ist, wechselt sie in den Wartezustand
  • Die Coroutine Nachdem die Ausführung von Programm 2 und Coroutine 3 abgeschlossen ist, sind die Daten push und Coroutine 1 erhält das Ergebnis und fährt mit der Ausführung fort

Verzögerte Aufgaben

🎜Bei der Coroutine-Programmierung müssen Sie möglicherweise einige Aufgaben automatisch ausführen und bereinigen, wenn die Coroutine beendet wird. Ähnlich wie PHPs register_shutdown_function kann es mit defer in Swoole4 implementiert werden. 🎜rrreee

Ausführungsergebnisse:

rrreee

Fazit

🎜Swoole4 bietet Go + Chan + Defer für PHP bringt ein neues <code>CSP-Modell für die gleichzeitige Programmierung. Durch die flexible Nutzung verschiedener von Swoole4 bereitgestellter Funktionen können das Design und die Entwicklung verschiedener komplexer Funktionen bei der Arbeit gelöst werden. 🎜🎜

Das obige ist der detaillierte Inhalt vonDetaillierte Erklärung der PHP-Coroutinen: Go + Chan + Defer. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Aktuelle Ausgaben
PHP-Datenerfassung?
Aus 1970-01-01 08:00:00
0
0
0
PHP-Erweiterung intl
Aus 1970-01-01 08:00:00
0
0
0
Wie man PHP gut lernt
Aus 1970-01-01 08:00:00
0
0
0
Mehrere PHP-Versionen
Aus 1970-01-01 08:00:00
0
0
0
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage