在swoole中,Swoole server接收資料在worker程序觸發onReceive回撥,產生一個協程,Swoole為每個請求建立對應攜程,協程中也能建立子協程,協程在底層實現上是單執行緒的,因此同一時間只有一個協程在工作。
本教學操作環境:Windows10系統、Swoole4版、DELL G3電腦
什麼是程序?
程序就是應用程式的啟動範例。獨立的檔案資源,資料資源,記憶體空間。
什麼是執行緒?
執行緒屬於程序,是程式的執行者。一個程序至少包含一個主執行緒,也可以有更多的子執行緒。執行緒有兩種排程策略,一是:分時排程,二是:搶佔式排程。
什麼是協程?
協程是輕量級執行緒,協程也是屬於執行緒,協程是線上程裡執行的。協程的排程是使用者手動切換的,所以又叫使用者空間執行緒。協程的建立、切換、掛起、銷燬全部為記憶體操作,消耗是非常低的。協程的排程策略是:共同作業式排程。
Swoole 協程的原理
Swoole4 由於是單執行緒多程序的,同一時間同一個程序只會有一個協程在執行。
Swoole server 接收資料在 worker 程序觸發 onReceive 回撥,產生一個攜程。Swoole 為每個請求建立對應攜程。協程中也能建立子協程。
協程在底層實現上是單執行緒的,因此同一時間只有一個協程在工作,協程的執行是序列的。
因此多工多協程執行時,一個協程正在執行時,其他協程會停止工作。當前協程執行阻塞 IO 操作時會掛起,底層排程器會進入事件迴圈。當有 IO 完成事件時,底層排程器恢復事件對應的協程的執行。。所以協程不存在 IO 耗時,非常適合高並行 IO 場景。(如下圖)
Swoole 的協程執行流程
協程沒有 IO 等待 正常執行 PHP 程式碼,不會產生執行流程切換
協程遇到 IO 等待 立即將控制權切,待 IO 完成後,重新將執行流切回原來協程切出的點
協程並行協程依次執行,同上一個邏輯
協程巢狀執行流程由外向內逐層進入,直到發生 IO,然後切到外層協程,父協程不會等待子協程結束
協程的執行順序
先來看看基礎的例子:
go(function () { echo "hello go1 \n";});echo "hello main \n";go(function () { echo "hello go2 \n";});
go() 是 \Co::create() 的縮寫, 用來建立一個協程, 接受 callback 作為引數, callback 中的程式碼, 會在這個新建的協程中執行.
備註: \Swoole\Coroutine 可以簡寫為 \Co
上面的程式碼執行結果:
root@b98940b00a9b /v/w/c/p/swoole# php co.phphello go1 hello main hello go2
執行結果和我們平時寫程式碼的順序, 好像沒啥區別. 實際執行過程:
執行此段程式碼, 系統啟動一個新程序
遇到 go(), 當前程序中生成一個協程, 協程中輸出 heelo go1, 協程退出
程序繼續向下執行程式碼, 輸出 hello main
再生成一個協程, 協程中輸出heelo go2, 協程退出
執行此段程式碼, 系統啟動一個新程序. 如果不理解這句話, 你可以使用如下程式碼:
// co.php<?phpsleep(100);
執行並使用 ps aux 檢視系統中的程序:
root@b98940b00a9b /v/w/c/p/swoole# php co.php &⏎ root@b98940b00a9b /v/w/c/p/swoole# ps auxPID USER TIME COMMAND 1 root 0:00 php -a 10 root 0:00 sh 19 root 0:01 fish 749 root 0:00 php co.php 760 root 0:00 ps aux
我們來稍微改一改, 體驗協程的排程:
use Co;go(function () { Co::sleep(1); // 只新增了一行程式碼 echo "hello go1 \n";});echo "hello main \n";go(function () { echo "hello go2 \n";}); \Co::sleep() 函數功能和 sleep() 差不多, 但是它模擬的是 IO等待(IO後面會細講). 執行的結果如下: root@b98940b00a9b /v/w/c/p/swoole# php co.phphello main hello go2 hello go1
怎麼不是順序執行的呢? 實際執行過程:
執行此段程式碼, 系統啟動一個新程序
遇到 go(), 當前程序中生成一個協程
協程中遇到 IO阻塞 (這裡是 Co::sleep() 模擬出的 IO等待), 協程讓出控制, 進入協程排程佇列
程序繼續向下執行, 輸出 hello main
執行下一個協程, 輸出 hello go2
之前的協程準備就緒, 繼續執行, 輸出 hello go1
到這裡, 已經可以看到 swoole 中 協程與程序的關係, 以及 協程的排程, 我們再改一改剛才的程式:
go(function () { Co::sleep(1); echo "hello go1 \n";});echo "hello main \n";go(function () { Co::sleep(1); echo "hello go2 \n";});
我想你已經知道輸出是什麼樣子了:
root@b98940b00a9b /v/w/c/p/swoole# php co.phphello main hello go1 hello go2
推薦學習:
以上就是swoole協程的實現原理是什麼的詳細內容,更多請關注TW511.COM其它相關文章!