Beispiel #1
0
 /**
  * @param \Generator $generator
  */
 public function __construct(Generator $generator)
 {
     parent::__construct();
     $this->generator = $generator;
     /**
      * @param mixed $value The value to send to the generator.
      */
     $this->send = function ($value = null) {
         if ($this->paused) {
             // If paused, save callable and value for resuming.
             $this->next = [$this->send, $value];
             return;
         }
         try {
             // Send the new value and execute to next yield statement.
             $this->next($this->generator->send($value));
         } catch (Throwable $exception) {
             $this->reject($exception);
             $this->close();
         }
     };
     /**
      * @param \Exception $exception Exception to be thrown into the generator.
      */
     $this->capture = function (Throwable $exception) {
         if ($this->paused) {
             // If paused, save callable and exception for resuming.
             $this->next = [$this->capture, $exception];
             return;
         }
         try {
             // Throw exception at current execution point.
             $this->next($this->generator->throw($exception));
         } catch (Throwable $exception) {
             $this->reject($exception);
             $this->close();
         }
     };
     try {
         $this->next($this->generator->current());
     } catch (Throwable $exception) {
         $this->reject($exception);
         $this->close();
     }
 }
Beispiel #2
0
 /**
  * [run 协程调度]
  * @param \Generator $gen
  * @throws \Exception
  */
 public function run(\Generator $gen)
 {
     while (true) {
         try {
             /* 异常处理 */
             if ($this->exception) {
                 $gen->throw($this->exception);
                 $this->exception = null;
                 continue;
             }
             $value = $gen->current();
             //                Logger::write(__METHOD__ . " value === " . var_export($value, true), Logger::INFO);
             /* 中断内嵌 继续入栈 */
             if ($value instanceof \Generator) {
                 $this->corStack->push($gen);
                 //                    Logger::write(__METHOD__ . " corStack push ", Logger::INFO);
                 $gen = $value;
                 continue;
             }
             /* if value is null and stack is not empty pop and send continue */
             if (is_null($value) && !$this->corStack->isEmpty()) {
                 //                    Logger::write(__METHOD__ . " values is null stack pop and send ", Logger::INFO);
                 $gen = $this->corStack->pop();
                 $gen->send($this->callbackData);
                 continue;
             }
             if ($value instanceof ReturnValue) {
                 $gen = $this->corStack->pop();
                 $gen->send($value->getValue());
                 // end yeild
                 //                    Logger::write(__METHOD__ . " yield end words == " . var_export($value, true), Logger::INFO);
                 continue;
             }
             /* 中断内容为异步IO 发包 返回 */
             if ($value instanceof \Swoole\Client\IBase) {
                 //async send push gen to stack
                 $this->corStack->push($gen);
                 $value->send(array($this, 'callback'));
                 return;
             }
             /* 出栈,回射数据 */
             if ($this->corStack->isEmpty()) {
                 return;
             }
             //                Logger::write(__METHOD__ . " corStack pop ", Logger::INFO);
             $gen = $this->corStack->pop();
             $gen->send($value);
         } catch (EasyWorkException $e) {
             if ($this->corStack->isEmpty()) {
                 throw $e;
             }
             $gen = $this->corStack->pop();
             $this->exception = $e;
         }
     }
 }
Beispiel #3
0
 /**
  * @param \Generator $generator
  */
 public function __construct(Generator $generator)
 {
     parent::__construct();
     $this->generator = $generator;
     /**
      * @param mixed $value The value to send to the generator.
      */
     $this->send = function ($value = null) {
         if ($this->busy) {
             Loop\queue($this->send, $value);
             // Queue continuation to avoid blowing up call stack.
             return;
         }
         try {
             // Send the new value and execute to next yield statement.
             $this->next($this->generator->send($value));
         } catch (Throwable $exception) {
             $this->reject($exception);
         }
     };
     /**
      * @param \Throwable $exception Exception to be thrown into the generator.
      */
     $this->capture = function (Throwable $exception) {
         if ($this->busy) {
             Loop\queue($this->capture, $exception);
             // Queue continuation to avoid blowing up call stack.
             return;
         }
         try {
             // Throw exception at current execution point.
             $this->next($this->generator->throw($exception));
         } catch (Throwable $exception) {
             $this->reject($exception);
         }
     };
     try {
         $this->next($this->generator->current());
     } catch (Throwable $exception) {
         $this->reject($exception);
     }
 }
Beispiel #4
0
 /**
  * Throw exception into generator.
  * @param \Throwable|\Exception $e
  * @NOTE: This method returns nothing,
  *        while original generator returns something.
  */
 public function throw_($e)
 {
     $this->validateValidity();
     try {
         $this->g->throw($e);
         return;
     } catch (\Throwable $e) {
     } catch (\Exception $e) {
     }
     $this->e = $e;
 }
Beispiel #5
0
 /**
  * @param \Generator $generator
  */
 public function __construct(Generator $generator)
 {
     parent::__construct();
     $this->generator = $generator;
     /**
      * @param mixed $value The value to send to the generator.
      */
     $this->send = function ($value = null) {
         if (null === $this->generator) {
             // Coroutine may have been cancelled.
             return;
         }
         try {
             // Send the new value and execute to next yield statement.
             $this->next($this->generator->send($value));
         } catch (Throwable $exception) {
             $this->reject($exception);
         }
     };
     /**
      * @param \Throwable $exception Exception to be thrown into the generator.
      */
     $this->capture = function (Throwable $exception) {
         if (null === $this->generator) {
             // Coroutine may have been cancelled.
             return;
         }
         try {
             // Throw exception at current execution point.
             $this->next($this->generator->throw($exception));
         } catch (Throwable $exception) {
             $this->reject($exception);
         }
     };
     try {
         $this->next($this->generator->current());
     } catch (Throwable $exception) {
         $this->reject($exception);
     }
 }
Beispiel #6
0
 /**
  * run coroutine
  * @return mixed
  */
 public function run()
 {
     if ($this->first_run) {
         $this->first_run = false;
         return $this->coroutine->current();
     }
     if ($this->exception instanceof \Exception) {
         $retval = $this->coroutine->throw($this->exception);
         $this->exception = null;
         return $retval;
     }
     $retval = $this->coroutine->send($this->send_value);
     $this->send_value = null;
     return $retval;
 }
Beispiel #7
0
function stackedCoroutine(Generator $gen)
{
    $stack = new SplStack();
    $exception = null;
    for (;;) {
        try {
            if ($exception) {
                $gen->throw($exception);
                $exception = null;
                continue;
            }
            $value = $gen->current();
            if ($value instanceof Generator) {
                $stack->push($gen);
                $gen = $value;
                continue;
            }
            $isReturnValue = $value instanceof CoroutineReturnValue;
            if (!$gen->valid() || $isReturnValue) {
                if ($stack->isEmpty()) {
                    return;
                }
                $gen = $stack->pop();
                $gen->send($isReturnValue ? $value->getValue() : NULL);
                continue;
            }
            if ($value instanceof CoroutinePlainValue) {
                $value = $value->getValue();
            }
            try {
                $sendValue = (yield $gen->key() => $value);
            } catch (Exception $e) {
                $gen->throw($e);
                continue;
            }
            $gen->send($sendValue);
        } catch (Exception $e) {
            if ($stack->isEmpty()) {
                throw $e;
            }
            $gen = $stack->pop();
            $exception = $e;
        }
    }
}
Beispiel #8
0
 /**
  * Runs the generator to completion then fails the coroutine with the given exception.
  *
  * @param \Throwable $exception
  */
 private function dispose(\Throwable $exception)
 {
     if ($this->generator->valid()) {
         try {
             try {
                 // Ensure generator has run to completion to avoid throws from finally blocks on destruction.
                 do {
                     $this->generator->throw($exception);
                 } while ($this->generator->valid());
             } finally {
                 // Throw from finally to attach any exception thrown from generator as previous exception.
                 throw $exception;
             }
         } catch (\Throwable $exception) {
             // $exception will be used to fail the coroutine.
         }
     }
     $this->fail($exception);
 }
Beispiel #9
0
 /**
  * {@inheritdoc}
  */
 public function cancel(Throwable $reason = null)
 {
     if (null === $reason) {
         $reason = new TerminatedException();
     }
     if (null !== $this->generator) {
         try {
             do {
                 if ($this->current instanceof Awaitable) {
                     $this->current->cancel($reason);
                 }
                 $this->current = $this->generator->throw($reason);
             } while ($this->generator->valid());
         } catch (Throwable $exception) {
             $reason = $exception;
         }
     }
     parent::cancel($reason);
 }
Beispiel #10
0
 /**
  * @brief 协程堆栈调度
  * @return type
  */
 public function run(\Generator $generator)
 {
     for (;;) {
         try {
             //异常处理
             if (null !== $this->_exception) {
                 $generator->throw($this->_exception);
                 $this->_exception = null;
                 continue;
             }
             //协程堆栈链的下一个元素
             $current = $generator->current();
             //协程堆栈链表的中断内嵌
             if ($current instanceof \Generator) {
                 $this->_coroutineStack->push($generator);
                 $generator = $current;
                 continue;
             }
             //syscall中断
             if ($current instanceof \Aha\Coroutine\SystemCall) {
                 return $current;
             }
             //retval中断
             $isReturnValue = $current instanceof \Aha\Coroutine\RetVal;
             if (!$generator->valid() || $isReturnValue) {
                 if ($this->_coroutineStack->isEmpty()) {
                     return;
                 }
                 $generator = $this->_coroutineStack->pop();
                 $generator->send($isReturnValue ? $current->getvalue() : $this->_sendValue);
                 $this->_sendValue = null;
             }
             //异步网络IO中断
             if ($this->_ahaInterrupt($current)) {
                 $this->_coroutineStack->push($generator);
                 return;
             }
             //当前协程堆栈元素可能有多次yeild 但是与父协程只有一次通信的机会 在通信前运行完
             $generator->send(is_null($current) ? $this->_sendValue : $current);
             $this->_sendValue = null;
             while ($generator->valid()) {
                 $current = $generator->current();
                 $generator->send(is_null($current) ? $this->_sendValue : $current);
                 $this->_sendValue = null;
             }
             //协程栈是空的 已经调度完毕
             if ($this->_coroutineStack->isEmpty()) {
                 return;
             }
             //把当前结果传给父协程栈
             $generator = $this->_coroutineStack->pop();
             $data = is_null($current) ? $this->_sendValue : $current;
             $this->_sendValue = null;
             $generator->send($data);
         } catch (\Exception $ex) {
             echo "[Coroutine_Task_Run_Exception]" . $ex->getMessage() . PHP_EOL;
             if ($this->_coroutineStack->isEmpty()) {
                 return;
             }
         }
     }
 }
Beispiel #11
0
 /**
  * @param \Generator $generator
  */
 public function __construct(Generator $generator)
 {
     $this->generator = $generator;
     parent::__construct(function (callable $resolve, callable $reject) {
         /**
          * @param mixed $value The value to send to the generator.
          * @param \Throwable|null $exception Exception object to be thrown into the generator if not null.
          */
         $this->worker = function ($value = null, Throwable $exception = null) use($resolve, $reject) {
             if ($this->paused) {
                 // If paused, mark coroutine as ready to resume.
                 $this->ready = true;
                 return;
             }
             try {
                 if ($this->initial) {
                     // Get result of first yield statement.
                     $this->initial = false;
                     $this->current = $this->generator->current();
                 } elseif (null !== $exception) {
                     // Throw exception at current execution point.
                     $this->current = $this->generator->throw($exception);
                 } else {
                     // Send the new value and execute to next yield statement.
                     $this->current = $this->generator->send($value);
                 }
                 if (!$this->generator->valid()) {
                     $resolve($this->generator->getReturn());
                     $this->close();
                     return;
                 }
                 if ($this->current instanceof Generator) {
                     $this->current = new self($this->current);
                 }
                 if ($this->current instanceof PromiseInterface) {
                     $this->current->done($this->worker, $this->capture);
                 } else {
                     Loop\queue($this->worker, $this->current);
                 }
             } catch (Throwable $exception) {
                 $reject($exception);
                 $this->close();
             }
         };
         /**
          * @param \Throwable $exception Exception to be thrown into the generator.
          */
         $this->capture = function (Throwable $exception) {
             if (null !== $this->worker) {
                 // Coroutine may have been closed.
                 ($this->worker)(null, $exception);
             }
         };
         Loop\queue($this->worker);
         return function (Throwable $exception) {
             try {
                 $current = $this->generator->current();
                 // Get last yielded value.
                 while ($this->generator->valid()) {
                     if ($current instanceof PromiseInterface) {
                         $current->cancel($exception);
                     }
                     $current = $this->generator->throw($exception);
                 }
             } finally {
                 $this->close();
             }
         };
     });
 }
Beispiel #12
0
 public function __call($method, $args)
 {
     if ($method === 'throw') {
         if (!$this->generator) {
             $this->rewind();
         }
         return $this->generator->throw(...$args);
     } else {
         // trigger normal undefined method error
         return $this->{$method}(...$args);
     }
 }
Beispiel #13
0
 /**
  * [run 协程调度]
  * @param  Generator $gen [description]
  * @return [type]         [description]
  */
 public function run(\Generator $gen)
 {
     while (true) {
         try {
             /*
                异常处理
             */
             if ($this->exception) {
                 $gen->throw($this->exception);
                 $this->exception = null;
                 continue;
             }
             $value = $gen->current();
             \SysLog::info(__METHOD__ . " value === " . print_r($value, true), __CLASS__);
             /*
                中断内嵌 继续入栈
             */
             if ($value instanceof \Generator) {
                 $this->corStack->push($gen);
                 \SysLog::info(__METHOD__ . " corStack push ", __CLASS__);
                 $gen = $value;
                 continue;
             }
             /*
                if value is null and stack is not empty pop and send continue
             */
             if (is_null($value) && !$this->corStack->isEmpty()) {
                 \SysLog::info(__METHOD__ . " values is null stack pop and send", __CLASS__);
                 $gen = $this->corStack->pop();
                 $gen->send($this->callbackData);
                 continue;
             }
             if ($value instanceof Swoole\Coroutine\RetVal) {
                 // end yeild
                 \SysLog::info(__METHOD__ . " yield end words == " . print_r($value, true), __CLASS__);
                 return false;
             }
             /*
                中断内容为异步IO 发包 返回
             */
             if (is_subclass_of($value, 'Swoole\\Client\\Base')) {
                 //async send push gen to stack
                 $this->corStack->push($gen);
                 $value->send(array($this, 'callback'));
                 return;
             }
             /*
                出栈,回射数据
             */
             if ($this->corStack->isEmpty()) {
                 return;
             }
             \SysLog::info(__METHOD__ . " corStack pop ", __CLASS__);
             $gen = $this->corStack->pop();
             $gen->send($value);
         } catch (\Exception $e) {
             if ($this->corStack->isEmpty()) {
                 /*
                     throw the exception 
                 */
                 \SysLog::error(__METHOD__ . " exception ===" . $e->getMessage(), __CLASS__);
                 return;
             }
         }
     }
 }
Beispiel #14
0
function stackedCoroutine(Generator $gen)
{
    $stack = new SplStack();
    echo "stack------\n";
    $i = 0;
    $exception = null;
    for (;;) {
        try {
            $i++;
            echo "i:::{$i}\n";
            if ($exception) {
                echo "stack exception \n ";
                var_dump($exception);
                $gen->throw($exception);
                $exception = null;
                continue;
            }
            $value = $gen->current();
            echo "stacked current  value:\n";
            var_dump($value);
            if ($value instanceof Generator) {
                echo "stacked is generator\n";
                $stack->push($gen);
                $gen = $value;
                continue;
            }
            $isReturnValue = $value instanceof CoroutineReturnValue;
            if (!$gen->valid() || $isReturnValue) {
                echo "stack empty\n";
                if ($stack->isEmpty()) {
                    return;
                }
                echo "stacked pop\n";
                var_dump($isReturnValue);
                $gen = $stack->pop();
                var_dump($gen);
                $gen->send($isReturnValue ? $value->getValue() : NULL);
                continue;
            }
            echo "stacked before end\n";
            //$gen->send("stack send 1");
            //  yield ;
            try {
                $s = (yield $gen->key() => $value);
                echo "stacked before end -----{$s}\n";
            } catch (Exception $e) {
                echo "stack sendvalue exception\n";
                var_dump($e);
                $gen->throw($e);
                continue;
            }
            $re = $gen->send($s);
            var_dump("stack:");
            var_dump($re);
            echo "stacked  end\n";
        } catch (Exception $e) {
            echo "stack exception last\n";
            var_dump($e);
            if ($stack->isEmpty()) {
                throw $e;
            }
            $gen = $stask->pop();
            $exception = $e;
        }
    }
}
Beispiel #15
0
 /**
  * @param \Generator $generator
  */
 public function __construct(Generator $generator)
 {
     $this->generator = $generator;
     parent::__construct(function (callable $resolve, callable $reject) {
         $yielded = $this->generator->current();
         if (!$this->generator->valid()) {
             $resolve($this->generator->getReturn());
             $this->close();
             return;
         }
         /**
          * @param mixed $value The value to send to the generator.
          */
         $this->send = function ($value = null) use($resolve, $reject) {
             if ($this->paused) {
                 // If paused, save callable and value for resuming.
                 $this->next = [$this->send, $value];
                 return;
             }
             try {
                 // Send the new value and execute to next yield statement.
                 $yielded = $this->generator->send($value);
                 if (!$this->generator->valid()) {
                     $resolve($this->generator->getReturn());
                     $this->close();
                     return;
                 }
                 $this->next($yielded);
             } catch (Throwable $exception) {
                 $reject($exception);
                 $this->close();
             }
         };
         /**
          * @param \Throwable $exception Exception to be thrown into the generator.
          */
         $this->capture = function (Throwable $exception) use($resolve, $reject) {
             if ($this->paused) {
                 // If paused, save callable and exception for resuming.
                 $this->next = [$this->capture, $exception];
                 return;
             }
             try {
                 // Throw exception at current execution point.
                 $yielded = $this->generator->throw($exception);
                 if (!$this->generator->valid()) {
                     $resolve($this->generator->getReturn());
                     $this->close();
                     return;
                 }
                 $this->next($yielded);
             } catch (Throwable $exception) {
                 $reject($exception);
                 $this->close();
             }
         };
         $this->next($yielded);
         return function (Throwable $exception) {
             try {
                 $current = $this->generator->current();
                 // Get last yielded value.
                 if ($current instanceof PromiseInterface) {
                     $current->cancel($exception);
                 }
             } finally {
                 $this->close();
             }
         };
     });
 }