swoole中有使用協程,協程主要用於將線程中的競爭資源轉化成協作運行;協程可以簡單理解為線程,是更加輕量級的線程,但是協程無法利用多核心CPU,適用於處理IO密集型任務、高並發服務等等。
本教學操作環境:Windows10系統、Swoole4版、DELL G3電腦
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 Swoole\Coroutine\MySQL(); $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 Swoole\Coroutine\Redis(); $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教學
以上是swoole中有使用協程嗎的詳細內容。更多資訊請關注PHP中文網其他相關文章!