ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
> 协程是一种轻量级的线程,由用户代码来调度和管理,而不是由操作系统内核来进行调度 > 一个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 ]; } ~~~