この記事は、一定の参考価値のある PHP Synergy に関する内容を共有するもので、困っている友人の助けになれば幸いです。
マルチプロセスとマルチスレッドが同時実行性を実現する効果的な方法であることはわかっています。ただし、マルチプロセスのコンテキスト切り替えリソースのオーバーヘッドは高すぎます。マルチスレッドのオーバーヘッドははるかに小さく、これは現在の主流の手法でもありますが、その制御はカーネル内にあるため、ユーザー (プログラマ) は制御を失います。コードとスレッドのコンテキスト切り替えにも一定のオーバーヘッドがかかります。このとき、上記の問題を解決するために「コルーチン」という概念が生まれました。コルーチンは、より軽量なスレッドと考えることができます。この種のスレッドは「ユーザー空間スレッド」と呼ばれます。コルーチンには次の 2 つの特徴があります:
コラボレーション。プログラマー自身が作成したスケジューリング戦略であるため、プリエンプションではなくコラボレーションを通じて切り替えます
作成、切り替え、および破棄はユーザー モードで完了します
PHP のコルーチンのサポートは 反復ジェネレーター に基づいており、ジェネレーターにデータを送り返す機能が追加されています (呼び出し元は呼び出されたジェネレーター関数にデータを送信します)。これにより、生成側から呼び出し側への一方向通信が、両者の間の双方向通信に変わります。
イテレータの概念については、ここでは詳しく説明しません。私たち自身で実装したイテレータを見てみましょう。
class MyIterator implements Iterator { private $var = array(); public function __construct($array) { if (is_array($array)) { $this->var = $array; } } public function rewind() { // 第一次迭代时候会执行(或调用该方法的时候),后面的迭代将不会执行。 echo "rewinding\n"; reset($this->var); } public function current() { $var = current($this->var); echo "current: $var\n"; return $var; } public function key() { $var = key($this->var); echo "key: $var\n"; return $var; } public function next() { // 最后执行,就是执行完下面sleep(2)后再执行。(执行了next本次迭代才算结束) $var = next($this->var); echo "next: $var\n"; return $var; } public function valid() { // 当valid返回false的时候迭代结束 $var = $this->current() !== false; echo "valid: {$var}\n"; return $var; } } $values = array(1,2,3,4); $it = new MyIterator($values); foreach ($it as $a => $b) { // 进行迭代(每次迭代,会依次执行以下方法: rewind(特别之处见上面解释), valid, current, key, next) print "=====\n"; sleep(2); }
出力:
rewinding current: 1 // 因为valid里面调用了current, 这里current出来一次 valid: 1 current: 1 key: 0 ===== next: 2 current: 2 valid: 1 current: 2 key: 1 ===== next: 3 current: 3 valid: 1 current: 3 key: 2 ===== next: 4 current: 4 valid: 1 current: 4 key: 3 ===== next: current: valid: // valid返回false,迭代结束
yeild を持つメソッドはジェネレーターです (ジェネレーターは Iterator インターフェイスを実装します。つまり、ジェネレーターはイテレータの特性)。ジェネレーターの実装は次のとおりです:
function xrange($start, $end, $step = 1) { for ($i = $start; $i <= $end; $i += $step) { echo $i . "\n"; yield; } } // foreach方式 foreach (xrange(1, 10) as $num) { } $gene = xrange(1, 10); // gene就是一个生成器对象 // current $gene->current(); // 打印1 // next $gene->next(); $gene->current() // 打印2
出力:
1 2 3 4 5 6 7 8 9 10 1 2
注:
ジェネレーターは関数のように直接呼び出すことはできません。呼び出し方法は次のとおりです:
1. 彼に連絡します
2. 送信 ($value)
3. 現在/次...
yield の構文は非常に柔軟なので、誰もが yield 構文の使い方を理解できるように、次の例を使用してみましょう。
ユース ケース 1: CPU 実行権を譲り渡す
function task1 () { for ($i = 1; $i <= 10; ++$i) { echo "This is task 1 iteration $i.\n"; yield;// 遇到yield就会主动让出CPU的执行权; } } $a = task1(); $a->current(); // 执行第一次迭代 $a->send(1); // 唤醒当时让出CPU执行权的yield
出力:
This is task 1 iteration 1. This is task 1 iteration 2.
// yield返回 function task2 () { for ($i = 1; $i <= 10; ++$i) { echo "This is task 2 iteration $i.\n"; yield "lm$i"; // 遇到yield就会主动让出CPU的执行权,for暂停执行, 然后返回"lm"。放在yield后面的值就是返回值 } } $a = task2(); $res = $a->current(); // 第一次迭代, 遇到yield返回 var_dump($res); $res = $a->send(1); // 唤醒yield, for继续执行,遇到yield返回。 var_dump($res);
出力:
This is task 2 iteration 1. string(3) "lm1" This is task 2 iteration 2. string(3) "lm2"
function task3 () { for ($i = 1; $i <= 10; ++$i) { echo "This is task 3 iteration $i.\n"; $getValue = yield;// 遇到yield就会主动让出CPU的执行权;send后,将send值赋值给getValue echo $getValue . " "; } } $a = task3(); $a->current(); $a->send("aa"); // 唤醒yield,并将"aa"值赋值给$getValue变量
出力:
This is task 3 iteration 1. aa This is task 3 iteration 2.
function task4 () { for ($i = 1; $i <= 10; ++$i) { echo "This is task 4 iteration $i.\n"; $ret = yield "lm$i"; // yield, 然后返回lm$i; 当send时,将send过来的值赋值给$ret; echo $ret; } } $a = task4(); var_dump($a->current()); // 返回lm1 var_dump($a->send("hhh ")); // 先唤醒yield, 将"hhh "赋值给$ret,再返回lm2 var_dump($a->send("www ")); // 先唤醒yield, 将"www "赋值给$ret,再返回lm3
出力:
This is task 4 iteration 1. string(3) "lm1"hhh This is task 4 iteration 2. string(3) "lm2"www This is task 4 iteration 3. string(3) "lm3"
関連する推奨事項:
PHP で抽象クラスとインターフェイスを使用する方法 (コード)
以上がPHPコルーチン内容の詳しい説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。