Swoole4
爲PHP
語言提供了強大的CSP
協程編程模式。底層提供了3
個關鍵詞,能夠方便地實現各種功能。php
Swoole4
提供的PHP協程
語法借鑑自Golang
,在此向GO
開發組致敬PHP+Swoole
協程能夠與Golang
很好地互補。Golang
:靜態語言,嚴謹強大性能好,PHP+Swoole
:動態語言,靈活簡單易用本文基於Swoole-4.2.9
和PHP-7.2.9
版本
go
:建立一個協程chan
:建立一個通道defer
:延遲任務,在協程退出時執行,先進後出這3
個功能底層實現所有爲內存操做,沒有任何IO
資源消耗。就像PHP
的Array
同樣是很是廉價的。若是有須要就能夠直接使用。這與socket
和file
操做不一樣,後者須要向操做系統申請端口和文件描述符,讀寫可能會產生阻塞的IO
等待。html
使用go
函數可讓一個函數併發地去執行。在編程過程當中,若是某一段邏輯能夠併發執行,就能夠將它放置到go
協程中執行。mysql
function test1() { sleep(1); echo "b"; } function test2() { sleep(2); echo "c"; } test1(); test2();
htf@LAPTOP-0K15EFQI:~$ time php b1.php bc real 0m3.080s user 0m0.016s sys 0m0.063s htf@LAPTOP-0K15EFQI:~$
上述代碼中,test1
和test2
會順序執行,須要3
秒才能執行完成。redis
使用go
建立協程,可讓test1
和test2
兩個函數變成併發執行。sql
Swoole\Runtime::enableCoroutine(); go(function () { sleep(1); echo "b"; }); go(function () { sleep(2); echo "c"; });
Swoole\Runtime::enableCoroutine()
做用是將PHP
提供的stream
、sleep
、pdo
、mysqli
、redis
等功能從同步阻塞切換爲協程的異步IO
bchtf@LAPTOP-0K15EFQI:~$ time php co.php bc real 0m2.076s user 0m0.000s sys 0m0.078s htf@LAPTOP-0K15EFQI:~$
能夠看到這裏只用了2
秒就執行完成了。shell
t1+t2+t3...
max(t1, t2, t3, ...)
有了go
關鍵詞以後,併發編程就簡單多了。與此同時又帶來了新問題,若是有2
個協程併發執行,另一個協程,須要依賴這兩個協程的執行結果,若是解決此問題呢?編程
答案就是使用通道(Channel
),在Swoole4
協程中使用new chan
就能夠建立一個通道。通道能夠理解爲自帶協程調度的隊列。它有兩個接口push
和pop
:swoole
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]); });
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$
這裏使用go
建立了3
個協程,協程2
和協程3
分別請求qq.com
和163.com
主頁。協程1
須要拿到Http
請求的結果。這裏使用了chan
來實現併發管理。app
1
循環兩次對通道進行pop
,由於隊列爲空,它會進入等待狀態2
和協程3
執行完成後,會push
數據,協程1
拿到告終果,繼續向下執行在協程編程中,可能須要在協程退出時自動實行一些任務,作清理工做。相似於PHP
的register_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"; });
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$
Swoole4
提供的Go + Chan + Defer
爲PHP
帶來了一種全新的CSP
併發編程模式。靈活使用Swoole4
提供的各項特性,能夠解決工做中各種複雜功能的設計和開發。