摘要:函數(shù)并不是生成器協(xié)程函數(shù)自動執(zhí)行的唯一方案。因為自動執(zhí)行的關鍵是,必須有一種機制,自動控制生成器協(xié)程函數(shù)的流程,接收和交還程序的執(zhí)行權。回調(diào)函數(shù)可以做到這一點,對象也可以做到這一點。本系列的下一篇,將介紹基于的實現(xiàn)的自動執(zhí)行器。
PHP下的異步嘗試系列
如果你還不太了解PHP下的生成器和協(xié)程,你可以根據(jù)下面目錄翻閱
PHP下的異步嘗試一:初識生成器
PHP下的異步嘗試二:初識協(xié)程
PHP下的異步嘗試三:協(xié)程的PHP版thunkify自動執(zhí)行器
PHP下的異步嘗試四:PHP版的Promise
[PHP下的異步嘗試五:PHP版的Promise的繼續(xù)完善]
高階函數(shù)在我們實現(xiàn)自動調(diào)度(器)函數(shù)前,我們先來理解下高階函數(shù)
thunk函數(shù)# 先求值再傳參 function func(m){ return m * 2; } f(x + 5); // 等同于 # 先傳參再求值 var thunk = function () { return x + 5; }; function func(thunk){ return thunk() * 2; } # 這段我們在python或一些語言里,概念叫高階函數(shù) # 因為php是解釋性動態(tài)語言,所以函數(shù)可以當參數(shù)傳入 # 這里python,js,php下函數(shù)都是可以傳參的PHP版本的thunkify函數(shù)
thunkify實現(xiàn)原理:
包裝一次原始函數(shù)名,然后返回一個第一次匿名函數(shù)(并攜帶包裝函數(shù)): return function () use ($func){$args = func_get_args();}
然后再獲取該匿名函數(shù)的參數(shù),并在上一次第一次匿名函數(shù)體內(nèi)返回一次帶回調(diào)參數(shù)的第二次匿名函數(shù)(并攜帶上一次環(huán)境上下文): return function ($callback) use ($args, $func){}
調(diào)用包裝函數(shù),參數(shù)為:第一次匿名函數(shù)調(diào)用的參數(shù)+一個回調(diào)函數(shù)
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" }只能執(zhí)行一次回調(diào)的thunkify函數(shù)
function thunkify($func){ return function () use ($func) { $args = func_get_args(); return function ($callback) use ($args, $func) { // 原本的獲取參數(shù),回調(diào)會多次執(zhí)行 // array_push($args, $callback); // 增加回調(diào)只能執(zhí)行一次 $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); //我們增加一次回調(diào) }; $printStrThunkify = thunkify($printStr); $printStrThunkify(...["foo", "bar"])(function (...$p) { var_dump($p); }); # output array(2) { [0]=> string(3) "foo" [1]=> string(3) "bar" }
看到這里,你可能還在疑惑,thunkify函數(shù)其實只是幫我們包裝了一次有回調(diào)函數(shù)的高階函數(shù)而已
不過這里到底有什么用處呢,在普通場景下確實用戶不大(可能用處單純就在做一些前后置函數(shù)包裝也是用處的,類似python的裝飾)
但是,但是,但是在生成器協(xié)程里,Thunkify函數(shù)可以用于生成器協(xié)程的自動流程管理。
每一次yield出來的結果都是一個thunk函數(shù)的回調(diào)
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(); // 手動回調(diào), 模擬自動執(zhí)行基礎理解 $value = $gen->current(); $value(function ($p1) use($gen) { $value = $gen->send($p1); $value(function ($p1) use($gen) { $value = $gen->send($p1); var_dump($value); }); });自動執(zhí)行器
我們這里只是實現(xiàn)上面的手動回調(diào)執(zhí)行
增加了一個自動執(zhí)行器,把生成器協(xié)程傳入后講自動執(zhí)行生成器協(xié)程
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的回調(diào) $result = $gen->current(); } else { // send后返回的是下一次的yield值 $result = $gen->send($p1); } // 是否生成器迭代完成 // 迭代器生成完成,不再迭代執(zhí)行(自動執(zhí)行器返回停止) 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里執(zhí)行的實際函數(shù)是同步的代碼,所以整體是阻塞的后續(xù)代碼執(zhí)行的總結
只要執(zhí)行 autoCaller 函數(shù),生成器就會自動迭代完成。這樣一來,異步操作不僅可以寫得像同步操作,而且一行代碼就可以執(zhí)行。
Thunkify函數(shù)并不是 生成器協(xié)程 函數(shù)自動執(zhí)行的唯一方案。
因為自動執(zhí)行的關鍵是,必須有一種機制,自動控制 生成器協(xié)程 函數(shù)的流程,接收和交還程序的執(zhí)行權。
回調(diào)函數(shù)可以做到這一點,Promise 對象也可以做到這一點。本系列的下一篇,將介紹基于PHP的Promise實現(xiàn)的自動執(zhí)行器。
附錄參考Thunk 函數(shù)的含義和用法 - 阮一峰
文章版權歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/30907.html
摘要:如果僅依靠程序自動交出控制的話,那么一些惡意程序?qū)苋菀渍加萌繒r間而不與其他任務共享。多個操作可以在重疊的時間段內(nèi)進行。 PHP下的異步嘗試系列 如果你還不太了解PHP下的生成器,你可以根據(jù)下面目錄翻閱 PHP下的異步嘗試一:初識生成器 PHP下的異步嘗試二:初識協(xié)程 PHP下的異步嘗試三:協(xié)程的PHP版thunkify自動執(zhí)行器 PHP下的異步嘗試四:PHP版的Promise ...
摘要:結果打印我結論或問題這里我們基礎實現(xiàn)了一個可以用于生產(chǎn)環(huán)境的后續(xù)我們會接續(xù)完善這個的特有方法,比如等后續(xù)再介紹用實現(xiàn)的自動執(zhí)行器等附錄參考中文對象入門阮一峰 PHP下的異步嘗試系列 如果你還不太了解PHP下的生成器和協(xié)程,你可以根據(jù)下面目錄翻閱 PHP下的異步嘗試一:初識生成器 PHP下的異步嘗試二:初識協(xié)程 PHP下的異步嘗試三:協(xié)程的PHP版thunkify自動執(zhí)行器 PHP下的...
摘要:下的異步嘗試系列下的異步嘗試一初識生成器下的異步嘗試二初識協(xié)程下的異步嘗試三協(xié)程的版自動執(zhí)行器下的異步嘗試四版的下的異步嘗試五版的的繼續(xù)完善生成器類獲取迭代器當前值獲取迭代器當前值返回當前產(chǎn)生的鍵生成器從上一次處繼續(xù)執(zhí)行重置迭代器向生成器中 PHP下的異步嘗試系列 PHP下的異步嘗試一:初識生成器 PHP下的異步嘗試二:初識協(xié)程 PHP下的異步嘗試三:協(xié)程的PHP版thunkify自...
摘要:傳統(tǒng)的異步方法回調(diào)函數(shù)事件監(jiān)聽發(fā)布訂閱之前寫過一篇關于的文章,里邊寫過關于異步的一些概念。內(nèi)部函數(shù)就是的回調(diào)函數(shù),函數(shù)首先把函數(shù)的指針指向函數(shù)的下一步方法,如果沒有,就把函數(shù)傳給函數(shù)屬性,否則直接退出。 Generator函數(shù)與異步編程 因為js是單線程語言,所以需要異步編程的存在,要不效率太低會卡死。 傳統(tǒng)的異步方法 回調(diào)函數(shù) 事件監(jiān)聽 發(fā)布/訂閱 Promise 之前寫過一篇關...
閱讀 3753·2021-10-13 09:39
閱讀 3804·2021-09-24 09:48
閱讀 1202·2021-09-01 10:30
閱讀 2533·2019-08-30 15:55
閱讀 1786·2019-08-29 16:39
閱讀 2304·2019-08-26 13:55
閱讀 3057·2019-08-26 12:23
閱讀 1643·2019-08-26 11:59