> 协程是一种轻量级的线程,由用户代码来调度和管理,而不是由操作系统内核来进行调度
> 一个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
];
}
~~~