PHPのコルーチン

コルーチン

  • コルーチン支持体が繰り返し発生器に基づいており、(発呼者が呼び出された関数発生器にデータを送信する)生成関数に送り返されるデータを増加させることができる。これは、呼び出し側双方向通信を変更するための発電機であります2間の双方向通信。

  • 関数は、ロガー()どのような通信動作のコルーチン例以下イテレータsend()メソッドの実装を介してデータを転送することです。

<?php
function logger($fileName) {
    $fileHandle = fopen($fileName, 'a');
    while (true) {
        fwrite($fileHandle, yield . "\n");
    }
}
 
$logger = logger(__DIR__ . '/log');
$logger->send('Foo');
$logger->send('Bar')
?>
  • あなたが見ることができるように、ここには歩留まりがステートメントとして使用されていないがありますが、表現として、それは価値へと進化させることができる。この値は、send()メソッドに渡され、呼び出し元の値がある。この例では、 、降伏式はまず、ログイン書かれた後、「バー」の代替ログ書か「foo」という選択肢となります。

  • 上記の例では、受信者として収量を示し、のは、同時に送受信する方法の例を見てみましょう:

<?php
function gen() {
    $ret = (yield 'yield1');  //这儿yield没有作为一个语句来使用, 而是用作一个表达式, 即它能被演化成一个值. 这个值就是调用者传递给send()方法的值
    var_dump($ret);
    $ret = (yield 'yield2');
    var_dump($ret);
}
 
$gen = gen();
var_dump($gen->current());        // string(6) "yield1"
var_dump($gen->send('ret1'));     // string(4) "ret1"   (the first var_dump in gen)
                                                      // string(6) "yield2" (the var_dump of the ->send() return value)
var_dump($gen->send('ret2'));     // string(4) "ret2"   (again from within gen)
                                                      // NULL               (the return value of ->send())
?>
  • 出力の正確な配列を理解するために、すぐに少し難しいかもしれないが、あなたは確かにあなたは、このように出力は。従うことを読み続ける理由を把握したいです。

  • また、私は二つのことを指摘しなければなりません。

  • 最初のポイント、PHP7前括弧内の式の両辺をもたらす任意ない、すなわち括弧内PHP5.5とPHP5.6で言うする必要があります。

  • 第二に、あなたは時間が巻き戻し操作を行う暗黙的に繰り返しオブジェクトを生成しているためです。)(何の巻き戻しを呼び出していない前に、コール電流を()気づいているかもしれません。

マルチタスクコラボレーション

  • あなたは上記のロガー()の例を読めば、あなたは不思議に思われるかもしれない「双方向通信のために、なぜ私はコルーチンを使用する必要がありますか?私は、同じ機能のああを達成するために、他の非コルーチンの方法を使うことができますか?」はい、あなたは正しいです。しかし、上記の例は、基本的な使用法を示すだけに、実際には、この例では、実際にコルーチンを使用することの利点を示すものではありません。

  • 上記の導入で述べたように、コルーチンは非常に強力な概念であるが、それは非常に稀であり、多くの場合、非常に複雑な使用しています。シンプルだが、実際のハードのいくつかの例を与えるために。

  • この記事では、私はあなたが同時に複数のタスク(または「プログラム」)を実行したいされて我々は問題を解決したい。マルチタスクコルーチン協力を使用することで行うことを決めた。しかし、我々はすべての時間だけで、そのCPUを知っています(マルチコア・ケースに関係なく)タスクを実行します。プロセッサは、各タスクと常に実行するように、異なるタスク間で切り替える必要があるので、「少しの間。」

  • どのようなスイッチの「コラボレーション」は非常に良い説明で用語の協力をマルチタスク:それはタスクが現在あなたがこの「プリエンプションを他のタスクを実行できるように戻って、スケジューラに制御を自動的に実行されている必要があり。 「代わりにマルチタスク、プリエンプティブマルチタスクは、このされています。Windows(Windows95の)およびMac OSの以前のバージョンで使用されているスケジューラは協調的マルチタスク、それはそれを好きかどうか、しばらくの間、タスクの操作を中断したりすることはできませんが、あります。プリエンプティブマルチタスク理由の使用後のスイッチは非常に明確である:あなたがプログラムに依存している場合は、自動的に制御を放棄し、一部の悪意あるプログラムは、簡単に他のタスクと共有しない、全体のCPUを占有します。

  • イールド命令が道タスクの中断自体を提供し、そしてそれゆえコルーチンはさらに、複数の他のタスクを実行することができ、タスクスケジューラに制御を返す:今、あなたはコルーチンとタスクのスケジューリングとの間の関係を理解する必要があります。 、収率は、タスクスケジューラとの間で通信するために使用することができます。

  • :軽量パッケージとコルーチン機能 - 私たちのマルチタスクスケジューリングを達成するために、「ミッション」を達成する最初の
<?php
class Task {
    protected $taskId;
    protected $coroutine;
    protected $sendValue = null;
    protected $beforeFirstYield = true;
 
    public function __construct($taskId, Generator $coroutine) {
        $this->taskId = $taskId;
        $this->coroutine = $coroutine;
    }
 
    public function getTaskId() {
        return $this->taskId;
    }
 
    public function setSendValue($sendValue) {
        $this->sendValue = $sendValue;
    }
 
    public function run() {
        if ($this->beforeFirstYield) {
            $this->beforeFirstYield = false;
            return $this->coroutine->current();
        } else {
            $retval = $this->coroutine->send($this->sendValue);
            $this->sendValue = null;
            return $retval;
        }
    }
 
    public function isFinished() {
        return !$this->coroutine->valid();
    }
}

このようなコードとしてタスクIDを持つタスクはコルーチン(機能)を使用するsetSendValue()メソッドのマークです、あなたは(あなたが私たちはこれを必要とすることを理解するであろう後)、次の回復に送信される値を指定することができ、実行()関数は、何を行うの共同プログラムの呼び出しが送信を除く()メソッド、beforeFirstYieldflag変数を追加理由を理解するために、次のコードを考慮していません。

<?php
function gen() {
    yield 'foo';
    yield 'bar';
}
 
$gen = gen();
var_dump($gen->send('something'));
 
// 如之前提到的在send之前, 当$gen迭代器被创建的时候一个renwind()方法已经被隐式调用
// 所以实际上发生的应该类似:
//$gen->rewind();
//var_dump($gen->send('something'));
 
//这样renwind的执行将会导致第一个yield被执行, 并且忽略了他的返回值.
//真正当我们调用yield的时候, 我们得到的是第二个yield的值! 导致第一个yield的值被忽略.
//string(3) "bar"
  • それは我々が最初に降伏の値を決定することができbeforeFirstYieldconditionを追加することにより、正しく返されます。

  • スケジューラは、今もう少しやるよりも、マルチタスキングのサイクルを持って、その後、単に複数のタスクを実行します。

おすすめ

転載: www.cnblogs.com/lz0925/p/11431389.html