ホームページ  >  記事  >  バックエンド開発  >  PHPコルーチンの自動実行プログラムthunkifyの詳細紹介(コード)

PHPコルーチンの自動実行プログラムthunkifyの詳細紹介(コード)

不言
不言転載
2018-10-09 14:08:272560ブラウズ

この記事では、PHP コルーチンの thunkify 自動実行プログラムについて詳しく紹介 (コード) しています。一定の参考価値があります。必要な友人は参照してください。お役に立てれば幸いです。

高階関数

自動スケジューリング(コントローラー)機能を実装する前に、まず高階関数について理解しましょう

サンク関数

# 先求值再传参
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下函数都是可以传参的

PHP バージョンの thunkify 関数

Thunkify 実装原則:

1. 元の関数名を 1 回ラップし、最初の匿名関数を返します (そして、ラッピング関数を実行します): return 関数() ($func){$args = func_get_args();}

2 を使用して、匿名関数のパラメーターを取得し、最後の最初の匿名関数の本体にコールバック パラメーターを指定して 2 回目を返します。匿名関数 (および最後の環境コンテキストを保持): return function ($callback) use ($args, $func){}

3. ラッパー関数を呼び出します。パラメータは次のとおりです: 最初の匿名関数のパラメータfunction call コールバック関数

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"
}

コールバックを 1 回だけ実行できる thunkify 関数

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"
}

これを見ると、まだ混乱するかもしれません。thunkify 関数は実際には、高レベルの関数をラップするのに役立つだけです。 function とコールバック関数。これは単なる関数です。
しかし、ここでの用途は何ですか? 通常のシナリオでは、確かにユーザーはそれほど多くありません (これは、Python と同様に、いくつかの関数前関数と関数後関数をラップするために単純に使用される可能性があります)装飾)
でも、でも、でも generator coroutine では Thunkify 関数 を使用して generator coroutine の自動プロセス管理を行うことができます。

ジェネレーター コルーチンの自動実行の基本的な理解

各 yield の結果はサンク関数のコールバックです

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);
    });
});

自動実行プログラム

ここでは、ここでのみ説明します。上記の手動コールバック実行を実装します。
自動エグゼキューターを追加しました。ジェネレーター コルーチンを渡した後、ジェネレーター コルーチンを自動的に実行します

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里执行的实际函数是同步的代码,所以整体是阻塞的后续代码执行的

要約

実行が続く限り autoCaller 関数を実行すると、ジェネレーターは完了するまで自動的に反復されます。このように、非同期操作は同期操作と同じように記述できるだけでなく、1 行のコードで実行することもできます。

Thunkify 関数は、generator coroutine 関数を自動実行するための唯一のソリューションではありません。

自動実行の鍵は、generator coroutine 関数の流れを自動的に制御し、プログラムの実行権を受け取り、返す仕組みが必要だからです。

コールバック関数はこれを行うことができ、Promise オブジェクトもこれを行うことができます。

以上がPHPコルーチンの自動実行プログラムthunkifyの詳細紹介(コード)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はsegmentfault.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。