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 类,并且还帮你处理了协程中可能会出现的异常情况,这样你在使用起来的时候就会更加方便且安全。

但是至于你最终选择哪个,完全取决于你的个人习惯,怎么顺手怎么来就行。

上一篇 下一篇

猜你喜欢

热点阅读