php 협 정 을 바탕 으로 비동기 적 인 방법 분석

4943 단어 php협정비동기
본 고의 실례 는 php 가 협정 을 바탕 으로 이 보 를 실현 하 는 방법 을 서술 하 였 다.여러분 께 참고 하도록 공유 하 겠 습 니 다.구체 적 으로 는 다음 과 같 습 니 다.
github 에서 phop 의 협 정 은 대부분 이 글 에 따라 이 루어 집 니 다.http://nikic.github.io/2012/12/22/Cooperative-multitasking-using-coroutines-in-PHP.html。
이들 의 최종 결 과 는 우아 한 순서 로 실 행 된 코드 로 바 뀌 었 지만 막 힌 것 은 진정한 비동기 가 아니다.
예 를 들 어 가장 핫 한 것:https://github.com/recoilphp/recoil
먼저 설치:

composer require recoil/recoil

실행:

<?php
//recoil.php
include __DIR__ . '/vendor/autoload.php';
use Recoil\React\ReactKernel;
$i = 100000;
ReactKernel::start(task1());
ReactKernel::start(task2());
function task1(){
  global $i;
  echo "wait start" . PHP_EOL;
  while ($i-- > 0) {
    yield;
  }
  echo "wait end" . PHP_EOL;
};
function task2(){
  echo "Hello " . PHP_EOL;
  yield;
  echo "world!" . PHP_EOL;
}

결과:
wait start
//몇 초 를 기다리다
wait end
Hello
world!
나 는 원래 두 가지 임 무 를 병행 시 키 려 고 했 는데,결국 두 가지 임 무 는 직렬 로 바 뀌 었 고,중간 에 기다 리 는 시간 에는 아무 일 도 할 수 없 었 다.React 응답 식 프로 그래 밍 은 이러한 기다 림 을 엄 격 히 금지 하기 때문에 저 는 유 니 티 3d 의 협 정 을 참조 하여 phop 버 전 을 썼 습 니 다.상위 코드:

<?php
//Coroutine.php
//  swoole      ,             
class Coroutine
{
  //             ,  ms
  const TICK_INTERVAL = 1;
  private $routineList;
  private $tickId = -1;
  public function __construct()
  {
    $this->routineList = [];
  }
  public function start(Generator $routine)
  {
    $task = new Task($routine);
    $this->routineList[] = $task;
    $this->startTick();
  }
  public function stop(Generator $routine)
  {
    foreach ($this->routineList as $k => $task) {
      if($task->getRoutine() == $routine){
        unset($this->routineList[$k]);
      }
    }
  }
  private function startTick()
  {
    swoole_timer_tick(self::TICK_INTERVAL, function($timerId){
      $this->tickId = $timerId;
      $this->run();
    });
  }
  private function stopTick()
  {
    if($this->tickId >= 0) {
      swoole_timer_clear($this->tickId);
    }
  }
  private function run()
  {
    if(empty($this->routineList)){
      $this->stopTick();
      return;
    }
    foreach ($this->routineList as $k => $task) {
      $task->run();
      if($task->isFinished()){
        unset($this->routineList[$k]);
      }
    }
  }
  
}
class Task
{
  protected $stack;
  protected $routine;
  public function __construct(Generator $routine)
  {
    $this->routine = $routine;
    $this->stack = new SplStack();
  }
  /**
   * [run     ]
   * @return [type]     [description]
   */
  public function run()
  {
    $routine = &$this->routine;
    try {
      if(!$routine){
        return;
      }
      $value = $routine->current();
      //     
      if ($value instanceof Generator) {
        $this->stack->push($routine);
        $routine = $value;
        return;
      }
      //       
      if(!$routine->valid() && !$this->stack->isEmpty()) {
        $routine = $this->stack->pop();
      }
      $routine->next();
    } catch (Exception $e) {
      if ($this->stack->isEmpty()) {
        /*
          throw the exception
        */
        return;
      }
    }
  }
  /**
   * [isFinished    task    ]
   * @return boolean [description]
   */
  public function isFinished()
  {
    return $this->stack->isEmpty() && !$this->routine->valid();
  }
  public function getRoutine()
  {
    return $this->routine;
  }
}

테스트 코드:

<?php
//test.php
 require 'Coroutine.php';
$i = 10000;
$c = new Coroutine();
$c->start(task1());
$c->start(task2());
function task1(){
  global $i;
  echo "wait start" . PHP_EOL;
  while ($i-- > 0) {
    yield;
  }
  echo "wait end" . PHP_EOL;
};
function task2(){
  echo "Hello " . PHP_EOL;
  yield;
  echo "world!" . PHP_EOL;
}

결과:
wait start
Hello
world!
//몇 초 기다 리 지만 막 히 지 않 습 니 다.
wait end
더 많은 PHP 관련 내용 에 관심 이 있 는 독자 들 은 본 사이트 의 주 제 를 볼 수 있다.
본 논문 에서 말 한 것 이 여러분 의 PHP 프로 그래 밍 에 도움 이 되 기 를 바 랍 니 다.

좋은 웹페이지 즐겨찾기