Maison >développement back-end >tutoriel php >Introduction détaillée de l'exécuteur automatique Thunkify de la coroutine PHP (code)

Introduction détaillée de l'exécuteur automatique Thunkify de la coroutine PHP (code)

不言
不言avant
2018-10-09 14:08:272681parcourir

Cet article vous apporte une introduction détaillée (code) sur l'exécuteur automatique thunkify des coroutines PHP. Il a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer.

Fonction d'ordre supérieur

Avant d'implémenter la fonction de planification automatique, comprenons d'abord la fonction d'ordre supérieur

fonction thunk

# 先求值再传参
function func(m){
  return m * 2;     
}
f(x + 5);
// 等同于

# 先传参再求值
var thunk = function () {
  return x + 5;
};

function func(thunk){
  return thunk() * 2;
}

# 这段我们在python或一些语言里,概念叫高阶函数
# 因为php是解释性动态语言,所以函数可以当参数传入
# 这里python,js,php下函数都是可以传参的

Version PHP de la fonction thunkify

Principe d'implémentation de Thunkify :

1. Enveloppez une fois le nom de la fonction d'origine, puis renvoyez une première fonction anonyme (et portez la fonction d'emballage) : return function ( ) utilisez ($func){$args = func_get_args();}

2. Récupérez ensuite les paramètres de la fonction anonyme et renvoyez le premier paramètre avec le paramètre de rappel dans le dernier corps de la fonction anonyme secondaire. fonction (et porte le dernier contexte d'environnement) : return function ($callback) use ($args, $func){}

3 Appelez la fonction wrapper, les paramètres sont : premier appel de fonction anonyme Paramètres + a. fonction de rappel

function thunkify($func){
    return function () use ($func) {
        $args = func_get_args();
        return function ($callback) use ($args, $func) {
            array_push($args, $callback);
            return $func(...$args);
        };
  };
};

$printStr = function($p1, $p2, $callback) {
    $callback($p1, $p2);
};

$printStrThunkify = thunkify($printStr);

$printStrThunkify(...["foo", "bar"])(function (...$p) {
    var_dump($p);
});

# output
array(2) {
  [0]=>
  string(3) "foo"
  [1]=>
  string(3) "bar"
}

Fonction Thunkify qui ne peut exécuter un rappel qu'une seule fois

function thunkify($func){
    return function () use ($func) {
        $args = func_get_args();
        return function ($callback) use ($args, $func) {
            // 原本的获取参数,回调会多次执行
            // array_push($args, $callback); 
            // 增加回调只能执行一次
            $callbackCalled = false;
            array_push($args, function (...$params) use ($callback, &$callbackCalled) {
                if ($callbackCalled) return ;
                $callbackCalled = true;
                $callback(...$params);
            });
            return $func(...$args);
        };
    };
};

$printStr = function($p1, $p2, $callback) {
    $callback($p1, $p2);
    $callback($p1, $p2); //我们增加一次回调
};

$printStrThunkify = thunkify($printStr);

$printStrThunkify(...["foo", "bar"])(function (...$p) {
    var_dump($p);
});

# output
array(2) {
  [0]=>
  string(3) "foo"
  [1]=>
  string(3) "bar"
}

En voyant cela, vous pouvez toujours être confus, la fonction thunkify ne fait en fait que l'envelopper pour nous C'est juste une fonction d'ordre supérieur avec une fonction de rappel
Mais à quoi ça sert ici ? Dans les scénarios ordinaires, elle n'a pas beaucoup d'utilisateurs (elle peut être utilisée simplement pour envelopper certaines fonctions pré- et post-fonction, similaire à la décoration python )
Mais, mais, mais dans 生成器协程, Thunkify函数 peut être utilisé pour la gestion automatique des processus de 生成器协程.

Compréhension de base de l'exécution automatique des coroutines du générateur

Le résultat de chaque rendement est un rappel d'une fonction thunk

function thunkify($func){
    return function () use ($func) {
        $args = func_get_args();
        return function ($callback) use ($args, $func) {
            $callbackCalled = false;
            array_push($args, function (...$params) use ($callback, &$callbackCalled) {
                if ($callbackCalled) return ;
                $callbackCalled = true;
                $callback(...$params);
            });
            return $func(...$args);
        };
    };
};

$printStr1 = function($p1, $callback) {
    $callback($p1);
};
$printStr2 = function($p1, $callback) {
    $callback($p1);
};

$printStrThunkify1 = thunkify($printStr1);
$printStrThunkify2 = thunkify($printStr2);

function gen()
{
    global $printStrThunkify1, $printStrThunkify2;

    $r1 = yield $printStrThunkify1("1");
    var_dump($r1);
    $r2 = yield $printStrThunkify2("2");
    var_dump($r2);
}

$gen = gen();

// 手动回调, 模拟自动执行基础理解
$value = $gen->current();
$value(function ($p1) use($gen) {
    $value = $gen->send($p1);
    $value(function ($p1) use($gen) {
        $value = $gen->send($p1);
        var_dump($value);
    });
});

Exécuteur automatique

Ici nous implémentons simplement l'exécution de rappel manuel ci-dessus
Ajoutez un exécuteur automatique, et après avoir passé la coroutine du générateur, nous exécuterons automatiquement la coroutine du générateur

function thunkify($func){
    return function () use ($func) {
        $args = func_get_args();
        return function ($callback) use ($args, $func) {
            $callbackCalled = false;
            array_push($args, function (...$params) use ($callback, &$callbackCalled) {
                if ($callbackCalled) return ;
                $callbackCalled = true;
                $callback(...$params);
            });
            return $func(...$args);
        };
    };
};

$printStr1 = function($p1, $callback) {
    sleep(2);
    $callback($p1);
};
$printStr2 = function($p1, $callback) {
    sleep(5);
    $callback($p1);
};

$printStrThunkify1 = thunkify($printStr1);
$printStrThunkify2 = thunkify($printStr2);

function gen()
{
    global $printStrThunkify1, $printStrThunkify2;

    $r1 = yield $printStrThunkify1("1");
    var_dump($r1);
    $r2 = yield $printStrThunkify2("2");
    var_dump($r2);
}

function autoCaller(\Generator $gen)
{
    // 注意这里的$next use 引入作用域必须带上&, 否则无法识别
    $next = function ($p1) use ($gen, &$next) {

        if (is_null($p1)) { //此处获取第一次yeild的回调
            $result = $gen->current();
        } else {
            // send后返回的是下一次的yield值
            $result = $gen->send($p1);
        }

        // 是否生成器迭代完成
        // 迭代器生成完成,不再迭代执行(自动执行器返回停止)
        if (!$gen->valid()) {
            return ;
        }

        $result($next);
    };

    $next(null);
}

$gen1 = gen();
//$gen2 = gen();

autoCaller($gen1);
//autoCaller($gen2);

# output
string(1) "1"
string(1) "2"

# 如果我们打开上面的两个sleep()注释
# output

# 等待2秒
string(1) "1"
# 等待5秒
string(1) "2"

# 因为这里我们的thunk里执行的实际函数是同步的代码,所以整体是阻塞的后续代码执行的

Résumé

Tant que la fonction autoCaller est exécutée, le générateur itérera automatiquement jusqu'à la fin. De cette manière, les opérations asynchrones peuvent non seulement être écrites comme des opérations synchrones, mais peuvent également être exécutées sur une seule ligne de code. La fonction

Thunkify n'est pas la seule solution pour l'exécution automatique de la fonction 生成器协程.

Parce que la clé de l'exécution automatique est qu'il doit y avoir un mécanisme pour contrôler automatiquement le flux de la fonction 生成器协程 et recevoir et restituer les droits d'exécution du programme.

Les fonctions de rappel peuvent le faire, tout comme les objets Promise.

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!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer