#Swoole4
為PHP
語言提供了強大的CSP
協程程式模式。底層提供了3
個關鍵字,可以方便實現各類功能。
-
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
等待。
推薦學習:《PHP影片教學》
協程並發
使用go
函數可以讓一個函數並發地去執行。在程式設計過程中,如果某一段邏輯可以並發執行,就可以將它放置到go
協程中執行。
順序執行
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
秒才能執行完成。
並發執行
使用go
建立協程,可以讓test1
和test2
兩個函數變成並發執行。
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秒就執行完成了。
- 順序執行耗時等於所有任務執行耗時的總和:
- t1 t2 t3...
- max(t1, t2, t3, ...)
go#關鍵詞之後,並發程式就簡單多了。同時又帶來了新問題,如果有
2個協程並發執行,另外一個協程,需要依賴這兩個協程的執行結果,如果解決此問題呢?
Channel),在
Swoole4協程中使用
new chan就可以建立一個頻道。通道可以理解為自帶協程調度的隊列。它有兩個介面
push和
pop:
- #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來實現並發管理。
- 協程
- 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提供的各項特性,可解決工作中各類複雜功能的設計與開發。