關於協程的優點以及swoole 協程的用法
- 2019 年 12 月 19 日
- 筆記
在上篇文章中php yield關鍵字以及協程的實現 我們講到了協程的原理以及運行步驟.
現在我們來繼續看下協程的執行順序.

協程的運行是交叉式運行(串列),只要你發起了一次協程切換,則會立馬暫停當前協程,去運行下一個協程,直到下次程式碼調度回協程.
協程的優點
看到上面的執行順序,你可能還是不能理解協程的優點,這個其實是一個很簡單的概念,舉個例子:
小明燒開水需要10分鐘,刷牙需要3分鐘,吃早餐需要5分鐘,請問做完這些事情總共需要多少分鐘?
答案是10分鐘,因為在燒開水這個步驟時,不需要坐在那裡看水壺燒(非同步,io耗時)可以先去刷牙,然後去吃早餐
協程的優點主要在於這裡,當遇上io耗時的情況時,這部分的等待時間我們其實可以節約出來,去先處理其他程式碼邏輯的,直到io完成再繼續執行之前的程式碼.
沒錯,協程的優點就在於這個.
swoole協程
在swoole中,已經自帶了協程管理器,以及非同步io的擴展(redis.mysql,http客戶端等),我們只要安裝好swoole擴展,就可以直接使用協程了,例如以下程式碼:
$start_time = time(); /*for ($i = 0; $i <= 500; $i++) { go(function ()use($i,$start_time){ $cli = new SwooleCoroutineHttpClient('www.baidu.com', 443,true); $cli->setHeaders([ 'Host' => "www.baidu.com", "User-Agent" => 'Chrome/49.0.2587.3', 'Accept' => 'text/html,application/xhtml+xml,application/xml', 'Accept-Encoding' => 'gzip', ]); $cli->set([ 'timeout' => 0.11]); $cli->get('/'); $cli->close(); echo "協程{$i}已完成,耗時".(time()-$start_time).PHP_EOL; }); }*/ $start_time = time(); for ($i = 0; $i <= 500; $i++) { $url = 'https://www.baidu.com/'; $content = file_get_contents($url); echo "普通{$i}已完成n"; } echo "非攜程完成時間:" . (time() - $start_time);
在非協程環境,它的執行順序和執行時間如下:

而在注釋掉非協程程式碼,協程環境運行下,它的執行順序和時間如下:

為什麼會這樣呢?我說下具體的流程:
非協程流程
1:先執行$i=0
2:通過file_get_contents獲取網頁內容
3:獲取成功後在進行輸出: 普通0已完成
4:繼續執行$i=1
…
協程流程
1:先執行$i=0
2:通過非同步client類,去請求https://www.baidu.com
3:協程切換不等待獲取網頁內容,直接跳到$i=1
4:通過非同步client類,去請求https://www.baidu.com
….
n:$i=0的請求內容已經完成,切換回$i=0後面的程式碼,輸出"協程0已完成,耗時0"
n+1:通過非同步client類,去請求https://www.baidu.com,協程切換不等待獲取網頁內容,直接跳到$i=n+2
n+2:$i=n的請求內容已經完成,切換回$i=n後面的程式碼,輸出"協程n已完成,耗時5"
….
由這2個流程可以看出一個不同之處:非協程需要等待請求網頁的時間,而協程直接跳過了等待的時間,繼續往下執行,
也就是上面說的"小明燒開水的時間先去刷牙"
然後,由於協程沒有了io耗時,執行速度大大提高,假設請求一次網站需要0.05秒,那500次循環就相當於節省了25秒,這就是為什麼協程適合在高並發io場景的原因了
本文為仙士可原創文章,轉載無需和我聯繫,但請註明來自仙士可部落格www.php20.cn
- 上一篇: 關於在windows上進行swoole開發的軟體使用
- 下一篇: php實現socket網路編程