Hyperf框架中开协程的几种方式
2024-03-18 本文已影响0人
左诗右码
基于 Hyperf 框架开协程的几种方式,你用过哪几种呢?
首先我们先在控制器中写一个方法,用于测试,本地默认启用 9516
端口,则测试路由为 127.0.0.1:9516/co/sleep
<?php
/**
* 开协程做请求
*
* Created by PhpStorm
* User: Alex
* Date: 2021-09-21 19:22
*/
declare(strict_types=1);
namespace App\Controller;
use Hyperf\Utils\Parallel;
use Hyperf\Utils\WaitGroup;
use Swoole\Coroutine\Channel;
use Hyperf\Guzzle\ClientFactory;
use Hyperf\HttpServer\Annotation\AutoController;
use Hyperf\HttpServer\Contract\RequestInterface;
use Hyperf\Di\Annotation\Inject;
/**
* @AutoController
* Class CoController
* @package App\Controller
*/
class CoController
{
/**
* @Inject
* @var ClientFactory
*/
private $clientFactory;
/**
* 方便测试超时操作
*
* @param RequestInterface $request
* @return mixed
*/
public function sleep(RequestInterface $request)
{
$seconds = $request->query('seconds', 1);
sleep((int)$seconds);
var_dump('sleep hello ====> ' . $seconds);
return $seconds;
}
}
第一种方式:使用 Channel 类做协程请求
/**
* 使用 Channel 做协程请求
*
* @return array
* @throws \GuzzleHttp\Exception\GuzzleException
*/
public function test()
{
$channel = new Channel();
co(function () use ($channel) {
$client = $this->clientFactory->create();
$client->get('127.0.0.1:9516/co/sleep?seconds=2');
$channel->push(123);
});
co(function () use ($channel) {
$client = $this->clientFactory->create();
$client->get('127.0.0.1:9516/co/sleep?seconds=2');
$channel->push(321);
});
$result[] = $channel->pop(); // 第一个协程返回的结果
$result[] = $channel->pop(); // 第二个协程返回的结果
return $result; // [123, 321]
}
第二种方式:使用 WaitGroup 类做协程请求
/**
* 使用 WaitGroup 做协程请求
*
* @return array
* @throws \GuzzleHttp\Exception\GuzzleException
*/
public function test1()
{
// 通过子协程并行的发起多个请求实现并行请求
$wg = new WaitGroup();
$wg->add(2); // 因为开了两个协程,因此就要添加 2
$result = [];
co(function () use ($wg, &$result) {
$client = $this->clientFactory->create();
$client->get('127.0.0.1:9516/co/sleep?seconds=2');
$result[] = 123;
$wg->done();
});
co(function () use ($wg, &$result) {
$client = $this->clientFactory->create();
$client->get('127.0.0.1:9516/co/sleep?seconds=2');
$result[] = 321;
$wg->done();
});
$wg->wait(); // 等待 add 计数器变为 0
return $result; // [321, 123]
}
第三种方式:使用 Parallel 类,做协程请求
/**
* 使用 Parallel 类,做协程请求
*
* @return array
*/
public function test2()
{
$parallel = new Parallel();
$parallel->add(function () {
$client = $this->clientFactory->create();
$client->get('127.0.0.1:9516/co/sleep?seconds=2');
return 123;
}, 'foo');
$parallel->add(function () {
$client = $this->clientFactory->create();
$client->get('127.0.0.1:9516/co/sleep?seconds=2');
return 321;
}, 'bar');
$result = $parallel->wait();
return $result; // {"foo":123,"bar":321}
}
第四种方式:使用 parallel 助手函数,做协程请求
/**
* 使用 parallel 助手函数,做协程请求
*
* @return array
*/
public function test3()
{
$result = parallel([
'foo' => function () {
$client = $this->clientFactory->create();
$client->get('127.0.0.1:9516/co/sleep?seconds=2');
return 123;
},
'bar' => function () {
$client = $this->clientFactory->create();
$client->get('127.0.0.1:9516/co/sleep?seconds=2');
return 321;
},
]);
return $result; // {"foo":123,"bar":321}
}
以上 4 种方式,如果你非要说让我推荐哪种,个人还是比较提倡使用 parallel助手函数的方式,感兴趣的童鞋可以去看看 parallel 助手函数的源码,你会发现其实也是使用到了 WaitGroup
类,并且还帮你处理了协程中可能会出现的异常情况,这样你在使用起来的时候就会更加方便且安全。
但是至于你最终选择哪个,完全取决于你的个人习惯,怎么顺手怎么来就行。