Explication détaillée du contenu de la coroutine PHP

不言
Libérer: 2023-04-03 13:46:01
original
1688 Les gens l'ont consulté

Cet article partage avec vous le contenu sur PHP Xiecheng. Il a une certaine valeur de référence. J'espère qu'il pourra aider les amis dans le besoin.

Concept

Nous savons que le multi-processus et le multi-thread sont des moyens efficaces pour atteindre la concurrence. Cependant, la surcharge de ressources de changement de contexte du multi-processus est trop élevée ; la surcharge du multi-threading est beaucoup plus petite, ce qui est également la pratique courante actuelle, mais son contrôle est dans le noyau, de sorte que l'utilisateur (programmeur) perd le contrôle de le code et le thread La commutation de contexte entraîne également une certaine surcharge. A cette époque, afin de résoudre les problèmes ci-dessus, le concept de « coroutine » est né. Vous pouvez considérer les coroutines comme des threads plus légers. Ce type de thread est appelé « thread de l’espace utilisateur ». Les coroutines ont les deux caractéristiques suivantes :

  1. Collaboration. Parce qu'il s'agit d'une stratégie de planification écrite par le programmeur lui-même, elle passe par collaboration plutôt que par préemption

  2. La création, la commutation et la destruction sont effectuées en mode utilisateur

Le support PHP des coroutines est basé sur le générateur itératif, ajoutant la fonction de renvoi de données au générateur (l'appelant envoie des données à la fonction générateur appelée). Cela transforme la communication unidirectionnelle du générateur vers l'appelant en une communication bidirectionnelle entre les deux.

Itérateur

La notion d'itérateur ne sera pas décrite ici. Jetons un coup d'œil à un itérateur que nous avons nous-mêmes implémenté.

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);
}
Copier après la connexion

Sortie :

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,迭代结束
Copier après la connexion

Générateur

La méthode de yeild est un générateur (le générateur implémente l'interface Iterator, c'est-à-dire , un générateur a les caractéristiques d’un itérateur). L'implémentation du générateur est la suivante :

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
Copier après la connexion

Sortie :

1
2
3
4
5
6
7
8
9
10
1
2
Copier après la connexion

Pour une explication détaillée de chaque méthode du générateur, veuillez consulter le document : http:/ /php.net/manual/zh/ class.generator.php

Remarque :

Le générateur ne peut pas être appelé directement comme une fonction. La méthode d'appel est la suivante :<🎜. >

1. pour chaque personne

2. envoyer($value)

3. actuel / suivant...

rendement

La syntaxe de rendement est très flexible, nous utilisons les exemples suivants afin que tout le monde puisse comprendre l'utilisation de la syntaxe de rendement.

Cas d'utilisation 1 : Rendement des droits d'exécution du processeur


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
Copier après la connexion
Sortie :

This is task 1 iteration 1.
This is task 1 iteration 2.
Copier après la connexion
Cas d'utilisation 2 : rendement du rendement

// 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);
Copier après la connexion
Sortie :

This is task 2 iteration 1.
string(3) "lm1"
This is task 2 iteration 2.
string(3) "lm2"
Copier après la connexion
Cas d'utilisation 3 : le rendement reçoit une valeur

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变量
Copier après la connexion
Sortie :

This is task 3 iteration 1.
aa This is task 3 iteration 2.
Copier après la connexion
Cas d'utilisation 4 : la réception et le retour du rendement sont écrits ensemble

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
Copier après la connexion
Sortie :

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"
Copier après la connexion
Recommandations associées :

Comment utiliser les classes et interfaces abstraites en PHP (code)

Implémentation du code de la pagination PHP et vérification régulière

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal
À propos de nous Clause de non-responsabilité Sitemap
Site Web PHP chinois:Formation PHP en ligne sur le bien-être public,Aidez les apprenants PHP à grandir rapidement!