swoole的協程channel容量理解和實例說明


首先翻到官網https://wiki.swoole.com/#/coroutine/channel

有關channel:通道,用於協程間通訊,支持多生產者協程和多消費者協程。底層自動實現了協程的切換和調度。

其構造方法:Swoole\Coroutine\Channel->__construct(int $capacity = 1),有個capacity的容量參數,一開始並不理解, 敲點代碼嘗試下,理解起來容易許多。

[root@guangzhou coroutine]# cat coroutine_channel.php
<?php
#開啟一鍵協程
Co::set(['hook_flags'=> SWOOLE_HOOK_ALL]);

Co\run(function(){
    // 設置一個容量為1的通道
    $chan = new Swoole\Coroutine\Channel(1);

    Swoole\Coroutine::create(function () use ($chan) {
        for($i = 0; $i < 6; $i++) {
        $chan->push( date('H:i:s') .  " 數據 i:" . $i . "\n");
            echo date('H:i:s') . " 第{$i}次塞數據時間\n";
        }
    });

    Swoole\Coroutine::create(function () use ($chan) {
        while(1) {
            $data = $chan->pop();
            if($data){
               echo  date('H:i:s') . " 取數據時間\n";
               echo $data . "\n";
               Co::sleep(2);
            }else{
               break;
            }
        }
    });
});
//看到這段代碼,你認為他的輸出情況是怎樣,先自己思考下!!

 

上面腳本運行后每次pop后獲取通道數據后休眠2秒,是協程模式,可能也會想當然認為每次取到數據的間隔應該是2秒??

現在運行腳本:

[root@guangzhou coroutine]# php coroutine_channel.php
06:55:32 第0次塞數據時間
06:55:32 第1次塞數據時間
06:55:32 取數據時間
06:55:32 數據 i:0

06:55:34 第2次塞數據時間
06:55:34 取數據時間
06:55:32 數據 i:1

06:55:36 第3次塞數據時間
06:55:36 取數據時間
06:55:32 數據 i:2

06:55:38 第4次塞數據時間
06:55:38 取數據時間
06:55:34 數據 i:3

06:55:40 第5次塞數據時間
06:55:40 取數據時間
06:55:36 數據 i:4

06:55:42 取數據時間
06:55:38 數據 i:5

 

有沒有發現前三次取數據時間點都是2秒的,第四次的數據一下子到了4秒。

經過swoole官方群的高人指點,給出了正確的執行路徑如下圖(數字從小到大是執行順序):

 

因為設置的capacity=1,導致第二次的push未成功,需要先pop方能繼續下去。

第一次pop后,回到第三次push循環,程序判斷管道已滿這時將處理第一次pop的數據,又開始第四次push循環,程序判斷管道又滿了,pop第二次push的數據。

到目前為止前三次push的數據並未進入到sleep這里,導致后續打印第一次pop數據時,塞數據時間點比取數據時間點被推后了。

從第三次數據pop后的數據都要經歷push失敗->echo+sleep->pop上一次的,這里就會有休眠2秒的時間加上pop上次時間就是4秒了。

這里有點繞,需要多思考並動手實踐。

 

修改capacity=10,並push循環7次,運行程序:

[root@guangzhou coroutine]# cat coroutine_channel.php
<?php
#開啟一鍵協程
Co::set(['hook_flags'=> SWOOLE_HOOK_ALL]);

Co\run(function(){
    // 設置一個容量為1的通道
    $chan = new Swoole\Coroutine\Channel(10);

    Swoole\Coroutine::create(function () use ($chan) {
        for($i = 0; $i < 7; $i++) {
        $chan->push( date('H:i:s') .  " 數據 i:" . $i . "\n");
            echo date('H:i:s') . " 第{$i}次塞數據時間\n";
        }
    });

    Swoole\Coroutine::create(function () use ($chan) {
        while(1) {
            $data = $chan->pop();
            if($data){
               echo  date('H:i:s') . " 取數據時間\n";
               echo $data . "\n";
               Co::sleep(2);
            }else{
               break;
            }
        }
    });
});

 

執行腳本:

[root@guangzhou coroutine]# php coroutine_channel.php
07:29:22 第0次塞數據時間
07:29:22 第1次塞數據時間
07:29:22 第2次塞數據時間
07:29:22 第3次塞數據時間
07:29:22 第4次塞數據時間
07:29:22 第5次塞數據時間
07:29:22 第6次塞數據時間
07:29:22 取數據時間
07:29:22 數據 i:0

07:29:24 取數據時間
07:29:22 數據 i:1

07:29:26 取數據時間
07:29:22 數據 i:2

07:29:28 取數據時間
07:29:22 數據 i:3

07:29:30 取數據時間
07:29:22 數據 i:4

07:29:32 取數據時間
07:29:22 數據 i:5

07:29:34 取數據時間
07:29:22 數據 i:6

發現所有 i:xxx 的時間點幾乎一致。

 

結論即是capacity的作用是限制管道寫入的長度,如果超出寫入長度限制則會寫入失敗,等數據pop后數據量少於capacity等數值才能push管道寫入成功。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM