swoole 协程并发调用封装简化使用流程

一、swoole 协程并发调用封装简化使用流程
创建waitCo类是为了简化并发协程调用逻辑
1.参考WaitGroup 计数方式改造而来。
2.嵌套一层异常捕获,防止协程异常错误导致程序报错。
3.运行协程函数可以配置提前defer函数或finally 协程资源释放,防止忘记释放资源造成资源一直占用。
4.很方便的可以获取到协程运行时长。
5.异常收集方便快速找到问题。

<?php
use Swoole\Coroutine;
use Swoole\Coroutine\Channel;

/**
 * Class WaitCo
 * @package box\co
 */
class WaitCo
{
    /**
     * @var Channel
     */
    protected Channel $channel;

    /**
     * 协程信息
     * @var array
     */
    protected array $coPool = [];

    /**
     * 等待标志
     * @var int
     */
    protected int $waiting = 0;

    /**
     * 错误信息
     * @var array
     */
    protected array $errorList = [];

    /**
     * 协程运行时长
     * @var array
     */
    protected array $coRunTime = [];


    /**
     * WaitCo constructor.
     */
    public function __construct()
    {
        $this->channel = new Channel(1);
    }

    /**
     * 创建协程
     */
    public function createCo(callable $fun)
    {
        if ($this->waiting === 2) {
            throw new \BadMethodCallException('WaitCo misuse: add called concurrently with wait');
        }
        if ($this->waiting === 3) {
            $this->coRunTime = [];
            $this->errorList = [];
        }
        $this->waiting = 1;
        $cid = Coroutine::create(function () use ($fun) {
            $cid = Coroutine::getCid();
            try {
                $fun();
            }catch (\Throwable $e) {
                $this->errorList[$cid] = ['code' => $e->getCode(), 'msg' => $e->getMessage(),'line' => $e->getLine()];
            } finally {
                $this->coRunTime[$cid] = $this->getMillisecond() - $this->coPool[$cid];
                unset($this->coPool[$cid]);
                //todo 释放协程内信息
                if (count($this->coPool) == 0) {
                    $this->channel->push(true);
                }
            }
        });
        if ($cid > 0) {
            $this->coPool[$cid] = $this->getMillisecond();
        }
    }

    /**
     * @param float|int $uTime
     * @return bool
     */
    public function wait(float $uTime = -1) : bool
    {
        if ($this->waiting !== 1) {
            throw new \BadMethodCallException('WaitCo misuse: reused before previous wait has returned');
        }
        if (count($this->coPool) < 0) {
            return true;
        }
        $cidList = array_keys($this->coPool);
        foreach ($cidList as $val) {
            if (!Coroutine::exists($val)) {
                unset($this->coPool[$val]);
            }
        }
        if (count($this->coPool) < 0) {
            return true;
        }
        $this->waiting = 2;
        $done = $this->channel->pop($uTime);
        $this->waiting = 3;
        return $done;
    }
    /**
     * 获取毫秒
     * @return string
     */
    public function getMillisecond(): string
    {
        list($s1, $s2) = explode(' ', microtime());
        return sprintf('%.0f', (floatval($s1) + floatval($s2)) * 1000);
    }

    /**
     * 获取错误信息
     */
    public function getErrorList():array
    {
        return $this->errorList;
    }

    /**
     * 获取运行时长
     * @return array
     */
    public function getTimeList():array
    {
        return $this->coRunTime;
    }
}

二、调用
1.通过createCo方法执行协程函数。
2.在最终获取结果时通过wait方法等待协程执行完毕。
3.getErrorList 获取异常信息 注意返回的key为协程id。
4.getTimeList 获取运行时长(毫秒) 注意返回的key为协程id。

<?php
Coroutine\run(function () {
    $result = [];//数据信息
    $waitCo = new WaitCo();
    $waitCo->createCo(function () use (&$result) {
        //todo 请求http,获取链接池db或redis 调用数据库
        Coroutine::sleep(1);
        $result["test"] = "你好";
    });
    $waitCo->createCo(function () use (&$result) {
        Coroutine::sleep(2);
        $result['test2'] = "哈哈";
    });
    $waitCo->createCo(function () use (&$result) {
        Coroutine::sleep(1);
        throw new Exception("co error");
        $result['exception'] = "test test";
    });
    $waitCo->wait();
    var_dump($result);
    var_dump($waitCo->getErrorList());
    var_dump($waitCo->getTimeList());
});

三、模拟运行输出
1.通过例子中可以看到result 应该可以获取到test与test2信息,exception由于异常中断了赋值操作。
2.通过getErrorList可以获取到异常。
3.通过getTimeList获取运行时长。

array(2) {
  ["test"]=>
  string(6) "你好"
  ["test2"]=>
  string(6) "哈哈"
}
array(1) {
  [4]=>
  array(3) {
    ["code"]=>
    int(0)
    ["msg"]=>
    string(8) "co error"
    ["line"]=>
    int(166)
  }
}
array(3) {
  [2]=>
  int(1023)
  [4]=>
  int(1024)
  [3]=>
  int(2016)
}
  • 7
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值