PHP協程(2):通過產生器棧實現非同步同步寫法____PHP

來源:互聯網
上載者:User

下面代碼中使用一個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 */
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.