swoole中有使用協程,協程主要用于將線程中的競爭資源轉化成協作運行;協程可以簡單理解為線程,是更加輕量級的線程,但是協程無法利用多核CPU,適用于處理IO密集型任務、高并發服務等等。
本教程操作環境:Windows10系統、Swoole4版、DELL G3電腦
swoole中有使用協程嗎
swoole中有使用協程
什么是協程
協程可以簡單理解為線程,只不過這個線程是用戶態的,不需要操作系統參與,創建銷毀和切換的成本非常低,和線程不同的是協程沒法利用多核 cpu 的,想利用多核 cpu 需要依賴 Swoole 的多進程模型。
協程特點
開發者可以無感知的用同步的代碼編寫方式達到異步 IO 的效果和性能,避免了傳統異步回調所帶來的離散的代碼邏輯和陷入多層回調中導致代碼無法維護。
同時由于底層封裝了協程,所以對比傳統的 php 層協程框架,開發者不需要使用 yield 關鍵詞來標識一個協程 IO 操作,所以不再需要對 yield 的語義進行深入理解以及對每一級的調用都修改為 yield,這極大的提高了開發效率。
協程適合 IO 密集型應用,因為協程在 IO 阻塞 時會自動調度,減少 IO 阻塞導致的時間損失。
睡眠 1 萬次,讀取,寫入,檢查和刪除文件 1 萬次,使用 pdo 和 mysqli 與數據庫通信 1 萬次,創建 TCP 服務器和多個客戶端相互通信 1 萬次,創建 udp 服務器和多個客戶端到相互通信 1 萬次… 一切都在一個進程一秒內完美完成!
適用場景
高并發服務,如秒殺系統、高性能API接口、rpc服務器,連接池,IM聊天、游戲服務器、物聯網、消息服務器等。
示例1:
用戶可以通過go函數創建一個協程,以達到并發執行的效果,如下面代碼所示:
go(function?()?{ ????echo?"one"?.?PHP_EOL; }); go(function?()?{ ????echo?"two"?.?PHP_EOL; }); go(function?()?{ ????echo?"three"?.?PHP_EOL; });
每當出現一個go,底層會自動創建一個協程,協程輸出內容后,然后自動退出
示例2:
通過協程可以并發執行客戶端請求,使用到協程調度帶來的 IO 阻塞時的調度,來實現高性能服務,下面是通過 defer 機制實現請求的并發執行:
go(function?()?{ ????//?協程?MySQL?客戶端 ????$mysql?=?new?SwooleCoroutineMySQL(); ????$mysql->connect([ ????????'host'?=>?'172.17.0.1', ????????'user'?=>?'root', ????????'password'?=>?'root', ????????'database'?=>?'swoole', ????]); ????$mysql->setDefer(); ????$mysql->query('select?sleep(2);'); ???? ?????print_r("time1:?"?.?time()?.?PHP_EOL); ???? ????//?協程?redis?客戶端 ????$redis?=?new?SwooleCoroutineRedis(); ????$redis->connect('172.17.0.1',?6379); ????$redis->setDefer(); ????$redis->set('name',?'張三'); ????$redis->recv(); ???? ????print_r("time2:?"?.?time()?.?PHP_EOL); ????$redis->setDefer(); ????$redis->get('name'); ????$res1?=?$mysql->recv(); ????$res2?=?$redis->recv(); ????print_r(['result1:?'?=>?$res1[0]['sleep'],?'result2:?'?=>?$res2,?'time3:?'?=>?time()]); });
以上述代碼為例,可以簡單理解為 defer 模式下, 多個客戶端的請求響應是并發的,設置 setDefer(true) 后,通過 Redis 或 MySQL 客戶端發起請求,將不再等待服務器返回結果,而是在發送請求之后,立即返回 true。在此之后可以繼續發起其他 Redis、MySQL 請求,最后再使用 recv() 方法接收響應內容。
注意事項
如果在多個協程間共用同一個協程客戶端,同步阻塞程序不同,協程是并發處理請求的,因此同一時間可能會有很多個請求在并行處理,一旦共用客戶端連接,就會導致不同協程之間發生數據錯亂。
協程使得原有的異步邏輯同步化,但是在協程的切換是隱式發生的,所以在協程切換的前后不能保證全局變量以及Static變量的一致性。
推薦學習: swoole教程