协程是一种轻量级的线程,由用户代码来调度和管理,而不是由操作系统内核来进行调度,也就是在用户态进。
一、 创建协程
co(callable $callable)【推荐】
go(callable $callable)
Hyperf\Coroutine\Coroutine::create(callable $callable)
二、使用协程【数据共享的三种方式】
1. Channel通道
<?php
namespace App\Controller;
use Hyperf\Di\Annotation\Inject;
use Hyperf\Guzzle\ClientFactory;
use Hyperf\HttpServer\Annotation\AutoController;
use Hyperf\HttpServer\Contract\RequestInterface;
use Swoole\Coroutine\Channel;
use function Hyperf\Coroutine\co;
#[AutoController]
class CoTestController
{
#[Inject]
private ClientFactory $client;
// 延时接口(模拟I/O操作)
public function sleep(RequestInterface $request)
{
$seconds = $request->query('seconds', 1);
sleep($seconds);
return $seconds;
}
public function test()
{
$channel = new Channel(); // 通过Channel通道 实现 协程间数据共享
co(function () use($channel) {
$client = $this->client->create();
$client->get('127.0.0.1:9501/co_test/sleep?seconds=2');
$channel->push(111);
});
co(function () use($channel) {
$client = $this->client->create();
$client->get('127.0.0.1:9501/co_test/sleep?seconds=2');
$channel->push(222);
});
$result[] = $channel->pop();
$result[] = $channel->pop();
return $result;
}
}
2. WaitGroup
<?php
namespace App\Controller;
use Hyperf\Coroutine\WaitGroup;
use Hyperf\Di\Annotation\Inject;
use Hyperf\Guzzle\ClientFactory;
use Hyperf\HttpServer\Annotation\AutoController;
use function Hyperf\Coroutine\co;
#[AutoController]
class WaitGroupTestController
{
#[Inject]
private ClientFactory $client;
public function test()
{
$wg = new WaitGroup();
$result = [];
$wg->add(2); // 计数器加2,与开启的协程数相同
co(function () use($wg, &$result) {
$client = $this->client->create();
$client->get('127.0.0.1:9501/co_test/sleep?seconds=2');
$result[] = 111;
$wg->done(); // 计数器减1
});
co(function () use($wg, &$result) {
$client = $this->client->create();
$client->get('127.0.0.1:9501/co_test/sleep?seconds=2');
$result[] = 222;
$wg->done(); // 计数器减1
});
$wg->wait(); // 等待协程 1 和协程 2 运行完成
return $result;
}
}
3. Parallel
<?php
namespace App\Controller;
use Hyperf\Coroutine\Parallel;
use Hyperf\Coroutine\WaitGroup;
use Hyperf\Di\Annotation\Inject;
use Hyperf\Guzzle\ClientFactory;
use Hyperf\HttpServer\Annotation\AutoController;
use function Hyperf\Coroutine\co;
#[AutoController]
class ParallelTestController
{
#[Inject]
private ClientFactory $client;
public function test()
{
$parallel = new Parallel();
$parallel->add(function () {
$client = $this->client->create();
$client->get('127.0.0.1:9501/co_test/sleep?seconds=2');
return 111;
}, 'foo'); // add方法的第2个参数为 返回值的索引,可选
$parallel->add(function () {
$client = $this->client->create();
$client->get('127.0.0.1:9501/co_test/sleep?seconds=2');
return 222;
}, 'bar');
// 协程运行结束后,返回结果
$result = $parallel->wait();
return $result;
}
}
4. parall助手函数【测试未通过】
// 使用 parallel全局函数的形式调用
public function test2()
{
$result = parallel([
'foo' => function () {
$client = $this->client->create();
$client->get('127.0.0.1:9501/co_test/sleep?seconds=2');
return 111;
},
'bar' => function () {
$client = $this->client->create();
$client->get('127.0.0.1:9501/co_test/sleep?seconds=2');
return 222;
}
]);
return $result;
}