在我們實現自動調度(器)函數前,我們先來理解下高階函數
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下函數都是可以傳參的PHP版本的thunkify函數
thunkify實現原理:
1、包裝一次原始函數名,然后返回一個第一次匿名函數(并攜帶包裝函數): return function () use ($func){$args = func_get_args();}
2、然后再獲取該匿名函數的參數,并在上一次第一次匿名函數體內返回一次帶回調參數的第二次匿名函數(并攜帶上一次環境上下文): return function ($callback) use ($args, $func){}
3、調用包裝函數,參數為:第一次匿名函數調用的參數+一個回調函數
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);# outputarray(2) { [0]= string(3) foo [1]= string(3) bar }只能執行一次回調的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);# outputarray(2) { [0]= string(3) foo [1]= string(3) bar }
看到這里,你可能還在疑惑,thunkify函數其實只是幫我們包裝了一次有回調函數的高階函數而已
不過這里到底有什么用處呢,在普通場景下確實用戶不大(可能用處單純就在做一些前后置函數包裝也是用處的,類似python的裝飾)
但是,但是,但是在生成器協程里,Thunkify函數可以用于生成器協程的自動流程管理。
每一次yield出來的結果都是一個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();// 手動回調, 模擬自動執行基礎理解$html' target='_blank'>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);# outputstring(1) 1 string(1) 2 # 如果我們打開上面的兩個sleep()注釋# output# 等待2秒string(1) 1 # 等待5秒string(1) 2 # 因為這里我們的thunk里執行的實際函數是同步的代碼,所以整體是阻塞的后續代碼執行的總結
只要執行 autoCaller 函數,生成器就會自動迭代完成。這樣一來,異步操作不僅可以寫得像同步操作,而且一行代碼就可以執行。
Thunkify函數并不是 生成器協程 函數自動執行的唯一方案。
因為自動執行的關鍵是,必須有一種機制,自動控制 生成器協程 函數的流程,接收和交還程序的執行權。
回調函數可以做到這一點,Promise 對象也可以做到這一點。
以上就是PHP協程的thunkify自動執行器的詳細介紹(代碼)的詳細內容,PHP教程
鄭重聲明:本文版權歸原作者所有,轉載文章僅為傳播更多信息之目的,如作者信息標記有誤,請第一時間聯系我們修改或刪除,多謝。
新聞熱點
疑難解答