> 協程是一種輕量級的線程,由用戶代碼來調度和管理,而不是由操作系統內核來進行調度
> 一個worker進程可以擁有多個協程(hf和swoole默認配置:一個進程最多100000個協程)
> HTTP 協程服務上來理解就是每一個請求是一個協程 (下文提到的主協程)
[TOC]
## 創建co協程
> 運行網頁:只占用6ms,協程不會占用主協程的時間
~~~
public function test()
{
co(function (){
sleep(5);
echo 'co backend process..';
});
return 'this is a test';
}
~~~
## Channel 通道
> Channel 主要用于協程間數據傳輸,多用在生產者協程和消費者協程
> 運行網頁:只占用 9ms,協程不會占用主協程的時間
~~~
public function test()
{
co(function () {
sleep(1);
$channel = new \Swoole\Coroutine\Channel();
co(function () use ($channel) {
sleep(2);
$channel->push('new data');
});
$data = $channel->pop();
var_dump($data);
});
return 'this is a test';
}
~~~
## WaitGroup 特性
> WaitGroup 是基于 Channel 衍生出來的一個特性
> WaitGroup 使得主協程一直阻塞等待所有的子協程都已經完成后再繼續運行,
> 這里說到的阻塞等待是僅對于主協程(即當前協程)來說的,并不會阻塞當前進程
> 運行網頁:只占用2.06s,主協程等待所有子協程完畢后才能繼續
~~~
public function test()
{
$wg = new \Hyperf\Utils\WaitGroup();
// 計數器加二
$wg->add(2);
// 創建協程 A
co(function () use ($wg) {
sleep(2); // some code
$wg->done();
});
// 創建協程 B
co(function () use ($wg) {
sleep(2); // some code
// 計數器減一
$wg->done();
});
// 等待協程 A 和協程 B 運行完成
$wg->wait();
return 'this is a test';
}
~~~
## Parallel 特性 (推薦)
> Parallel 基于 WaitGroup 特性抽象出來的一個更便捷的使用方法
> 運行網頁:只占用2.09s,主協程等待所有子協程完畢后才能繼續
~~~
public function test()
{
$parallel = new Parallel();
$parallel->add(function () {
sleep(2);
return Coroutine::id();
});
$parallel->add(function () {
sleep(2);
return Coroutine::id();
});
try{
// $result 結果為 [1, 2]
$result = $parallel->wait();
} catch(ParallelExecutionException $e){
// $e->getResults() 獲取協程中的返回值。
// $e->getThrowables() 獲取協程中出現的異常。
}
return $result;
}
~~~
## 協程應用案例1
> 加速商品數據取值: 程序中參雜著`增加商品瀏覽量`等其他功能,這些支線功能模塊,就可以放到協程里
> 以下案例:主線僅花費6ms完成,協程里的5秒運行是在后端運行,不會影響主線的程序執行
~~~
public function test()
{
$id = get("id");
$product = Product::findOne($id);
co(function () use $product{
sleep(5);
$product->view_num += 1;
$product->save();
echo 'co backend processed..';
});
return 'this is a test';
}
~~~
## 協程應用案例2
> 加速商品數據取值: 放入Parallel中并行讀取數據
~~~
public function test()
{
$parallel = new Parallel();
$parallel->add(function () {
sleep(2);
return Product::findOne(2);
});
$parallel->add(function () {
sleep(2);
return Product::find()->where(['type'=>3])->all();
});
try{
// $result 結果為 [obj, list]
$result = $parallel->wait();
} catch(ParallelExecutionException $e){
// $e->getResults() 獲取協程中的返回值。
// $e->getThrowables() 獲取協程中出現的異常。
}
$product = $result[0];
$hotList = $result[1];
return [
'product' => $product,
'hotList' => $hotList
];
}
~~~