PHP协程(2):通过生成器栈实现异步的同步写法

2 篇文章 0 订阅

下面代码中使用一个TaskStack生成器栈,实现了异步方法swoole_timer_after的同步写法;顺带还实现了子生成器的调用;
只要是有callback方法的异步操作,均可以使用一下方式实现异步操作的同步写法;

class TaskStack
{

    public $stack;
    public $generator;
    public $return;

    public function __construct(Generator $generator)
    {
        $this->stack = new SplStack();
        $this->generator = $generator;
    }

    public function run()
    {
        while (1) {
            try {
                if (!$this->generator->valid()) {
                    if (!$this->stack->isEmpty()) {
                        try {
                            $this->return = $this->generator->getReturn();
                        } catch (Exception $e) {
                            $this->return = null;
                        }
                        $this->generator = $this->stack->pop();
                        /**
                         * 将子generator里面的返回值赋予父generator当前的yield表达式作为结果值;
                         * 并且执行下一个父级yield表达式;
                         * 如果这里不执行下一个父级yield表达式,generator会一直在这个yield,在下面会死循环;
                         */
                        // 下面 子generator执行逻辑分析 中的send方法;
                        $this->generator->send($this->return);
                        continue;
                    }
                    return;
                }
                /**
                 * 子generator执行逻辑分析:
                 *      1.获取当前yield表达式的结果值result;
                 *      2.如果result是一个generator生成器;
                 *      3.那么将当前执行的generator入栈(当前执行的生成器为TaskStack类中的generator属性);
                 *      4.执行子generator,子generator执行完毕,获取返回值;
                 *      ## 这一刻的send方法作用,巧妙绝伦的设计;
                 *      # 5.send方法将子generator的返回值作为父generator中断的yield表达式的结果值;
                 *      # 6.继续执行父generator;
                 *      ## 如果没有5和6,那么在4执行完毕之后又回到1,死循环;
                 */
                $this->return = $this->generator->current();
                if ($this->return instanceof Generator) {
                    $this->stack->push($this->generator);
                    $this->generator = $this->return;
                    continue;
                }
                /**
                 * 异步执行逻辑分析:
                 *      1.获取当前yield表达式的值result;
                 *      2.如果result是一个特殊的异步类(自定义的类或者接口用来处理异步操作);
                 *      3.向异步的回调函数中发送闭包函数Closure,也就是说当异步操作完成,执行回调函数的时候,会执行发送的Closure;
                 *      Closure中操作:
                 *          1.通过send方法,将异步执行的结果发送到当前执行到的yield表达式作为结果值;
                 *          2.继续执行TaskStack的run(),继续执行生成器;
                 *      4.直接结束栈的run()方法;
                 *
                 *      ## 结合来说也就是说如果遇到一个表达式的值为异步类,
                 *      ## 那么直接结束当前TaskStack的执行,直到异步回调函数执行,才恢复执行;
                 *      ## 注意,这里生成器停止执行,对于进程来说并不是阻塞的,此时进程可以执行别的操作;
                 */
                if ($this->return instanceof AsyncSSS) {
                    $this->return->delivery(function () {
                        echo "time " . time() . PHP_EOL;
                        $this->generator->send("async return");
                        $this->run();
                    });
                    return;
                }
                $this->generator->send($this->return);
            } catch (Exception $e) {
                throw $e;
            }
        }
    }

    public function end()
    {
        return $this->stack->isEmpty() && !$this->generator->valid();
    }

}

class AsyncSSS
{

    public $second;

    public function after($second)
    {
        $this->second = $second;
        return $this;
    }

    public function delivery(Closure $callback)
    {
        swoole_timer_after($this->second, $callback);
    }

}

function task1()
{
    echo "task1 before" . PHP_EOL;
    echo "time " . time() . PHP_EOL;
    $async = yield (new AsyncSSS)->after(3000);
    echo "task1 get async return value : $async" . PHP_EOL;
    $generator = yield task1_1();
    echo "task1 get task2 return value : $generator" . PHP_EOL;
    echo "task1 after" . PHP_EOL;
}

function task1_1()
{
    echo "task1_1 before" . PHP_EOL;
    $value = yield task1_1_1();
    echo "task1_1 get task1_1_1 return value : $value" . PHP_EOL;
    echo "task1_1 after" . PHP_EOL;
    return 'task1_1 return';
}

function task1_1_1()
{
    return "task1_1_1 return";
}

$a = new TaskStack(task1());
$a->run();
echo 'task stack run after' . PHP_EOL;

/**
 * 输出:
 * task1 before
 * time 1511331788
 * task stack run after
 * time 1511331791
 * task1 get async return value : async return
 * task1_1 before
 * task1_1 get task1_1_1 return value : task1_1_1 return
 * task1_1 after
 * task1 get task2 return value : task1_1 return
 * task1 after
 */
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值