摘要:的返回值是傳遞給方法的值。上面的例子演示了基本用法,然而上下文中沒有真正的展示出使用協程的優點。這個時候你應當明白協程和任務調度之間的聯系指令提供了任務中斷自身的一種方法,然后把控制傳遞給調度器。因此協程可以運行多個其他任務。
協程是比較少見的概念,先轉過來作為參考,需要時應該可以用到
轉自:http://www.oschina.net/transl...
生成器最基本的思想也是一個函數,這個函數的返回值是依次輸出,而不是只返回一個多帶帶的值。或者,換句話說,生成器使你更方便的實現了迭代器接口。下面通過實現一個xrange函數來簡單說明:
上面這個xrange()函數提供了和PHP的內建函數range()一樣的功能。但是不同的是range()函數返回的是一個包含屬組值從1到100萬的數組(注:請查看手冊)。而xrange()函數返回的是依次輸出這些值的一個迭代器,而且并不會真正以數組形式計算。
這種方法的優點是顯而易見的。它可以讓你在處理大數據集合的時候不用一次性的加載到內存中。甚至你可以處理無限大的數據流。
當然,也可以不同通過生成器來實現這個功能,而是可以通過繼承Iterator接口實現。通過使用生成器實現起來會更方便,而不用再去實現iterator接口中的5個方法了。
生成器為可中斷的函數要從生成器認識協同程序,理解它們內部是如何工作的非常重要:生成器是可中斷的函數,在它里面,yield構成了中斷點。?
緊接著上面的例子,如果你調用xrange(1,1000000)的話,xrange()函數里代碼沒有真正地運行。相反,PHP只是返回了一個實現了迭代器接口的 生成器類實例:?
?
?
?
協程
協程給上面功能添加的主要東西是回送數據給生成器的能力。這將把生成器到調用者的單向通信轉變為兩者之間的雙向通信。
?
send("Foo"); $logger->send("Bar")正如你能看到,這兒yield沒有作為一個語句來使用,而是用作一個表達式。即它有一個返回值。yield的返回值是傳遞給send()方法的值。 在這個例子里,yield將首先返回"Foo",然后返回"Bar"。
上面的例子里yield僅作為接收者。混合兩種用法是可能的,即既可接收也可發送。接收和發送通信如何進行的例子如下:
current()); // string(6) "yield1" var_dump($gen->send("ret1")); // string(4) "ret1" (the first var_dump in gen) // string(6) "yield2" (the var_dump of the ->send() return value) var_dump($gen->send("ret2")); // string(4) "ret2" (again from within gen) // NULL (the return value of ->send())多任務協作
如果閱讀了上面的logger()例子,那么你認為“為了雙向通信我為什么要使用協程呢? 為什么我不能只用常見的類呢?”,你這么問完全正確。上面的例子演示了基本用法,然而上下文中沒有真正的展示出使用協程的優點。這就是列舉許多協程例子的理由。正如上面介紹里提到的,協程是非常強大的概念,不過這樣的應用很稀少而且常常十分復雜。給出一些簡單而真實的例子很難。
多任務協作這個術語中的“協作”說明了如何進行這種切換的:它要求當前正在運行的任務自動把控制傳回給調度器,這樣它就可以運行其他任務了。這與“搶占”多任務相反,搶占多任務是這樣的:調度器可以中斷運行了一段時間的任務,不管它喜歡還是不喜歡。協作多任務在Windows的早期版本(windows95)和Mac OS中有使用,不過它們后來都切換到使用搶先多任務了。理由相當明確:如果你依靠程序自動傳回 控制的話,那么壞行為的軟件將很容易為自身占用整個CPU,不與其他任務共享。?
這個時候你應當明白協程和任務調度之間的聯系:yield指令提供了任務中斷自身的一種方法,然后把控制傳遞給調度器。因此協程可以運行多個其他任務。更進一步來說,yield可以用來在任務和調度器之間進行通信。
我們的目的是 對 “任務”用更輕量級的包裝的協程函數:
taskId = $taskId; $this->coroutine = $coroutine; } public function getTaskId() { return $this->taskId; } public function setSendValue($sendValue) { $this->sendValue = $sendValue; } public function run() { if ($this->beforeFirstYield) { $this->beforeFirstYield = false; return $this->coroutine->current(); } else { $retval = $this->coroutine->send($this->sendValue); $this->sendValue = null; return $retval; } } public function isFinished() { return !$this->coroutine->valid(); } }?
任務ID標記
send("something")); // As the send() happens before the first yield there is an implicit rewind() call, // so what really happens is this: $gen->rewind(); var_dump($gen->send("something")); // The rewind() will advance to the first yield (and ignore its value), the send() will // advance to the second yield (and dump its value). Thus we loose the first yielded value!調度器現在不得不比多任務循環要做稍微多點了,然后才運行多任務:
task protected $taskQueue; public function __construct() { $this->taskQueue = new SplQueue(); } public function newTask(Generator $coroutine) { $tid = ++$this->maxTaskId; $task = new Task($tid, $coroutine); $this->taskMap[$tid] = $task; $this->schedule($task); return $tid; } public function schedule(Task $task) { $this->taskQueue->enqueue($task); } public function run() { while (!$this->taskQueue->isEmpty()) { $task = $this->taskQueue->dequeue(); $task->run(); if ($task->isFinished()) { unset($this->taskMap[$task->getTaskId()]); } else { $this->schedule($task); } } } }?
?
newTask(task1()); $scheduler->newTask(task2()); $scheduler->run();This is task 1 iteration 1. This is task 2 iteration 1. This is task 1 iteration 2. This is task 2 iteration 2. This is task 1 iteration 3. This is task 2 iteration 3. This is task 1 iteration 4. This is task 2 iteration 4. This is task 1 iteration 5. This is task 2 iteration 5. This is task 1 iteration 6. This is task 1 iteration 7. This is task 1 iteration 8. This is task 1 iteration 9. This is task 1 iteration 10.與調度器之間通信?既然調度器已經運行了,那么我們就轉向日程表的下一項:任務和調度器之間的通信。我們將使用進程用來和操作系統會話的同樣的方式來通信:系統調用。我們需要系統調用的理由是操作系統與進程相比它處在不同的權限級別上。因此為了執行特權級別的操作(如殺死另一個進程),就不得不以某種方式把控制傳回給內核,這樣內核就可以執行所說的操作了。再說一遍,這種行為在內部是通過使用中斷指令來實現的。過去使用的是通用的int指令,如今使用的是更特殊并且更快速的syscall/sysenter指令。
為了說明系統調用,我將對可調用的系統調用做一個小小的封裝:
callback = $callback; } public function __invoke(Task $task, Scheduler $scheduler) { $callback = $this->callback; // Can"t call it directly in PHP :/ return $callback($task, $scheduler); } }taskQueue->isEmpty()) { $task = $this->taskQueue->dequeue(); $retval = $task->run(); if ($retval instanceof SystemCall) { $retval($task, $this); continue; } if ($task->isFinished()) { unset($this->taskMap[$task->getTaskId()]); } else { $this->schedule($task); } } }setSendValue($task->getTaskId()); $scheduler->schedule($task); }); }newTask(task(10)); $scheduler->newTask(task(5)); $scheduler->run();setSendValue($scheduler->newTask($coroutine)); $scheduler->schedule($task); } ); } function killTask($tid) { return new SystemCall( function(Task $task, Scheduler $scheduler) use ($tid) { $task->setSendValue($scheduler->killTask($tid)); $scheduler->schedule($task); } ); }?killTask函數需要在調度器里增加一個方法:
taskMap[$tid])) { return false; } unset($this->taskMap[$tid]); // This is a bit ugly and could be optimized so it does not have to walk the queue, // but assuming that killing tasks is rather rare I won"t bother with it now foreach ($this->taskQueue as $i => $task) { if ($task->getTaskId() === $tid) { unset($this->taskQueue[$i]); break; } } return true; }newTask(task()); $scheduler->run();?這段代碼將打印以下信息:
Parent task 1 iteration 1. Child task 2 still alive! Parent task 1 iteration 2. Child task 2 still alive! Parent task 1 iteration 3. Child task 2 still alive! Parent task 1 iteration 4. Parent task 1 iteration 5. Parent task 1 iteration 6.
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/30562.html
摘要:今天,大會召開,在這場規模三萬人的盛會上,宣布推出作為多云服務新方案,提供跨云目前僅支持和管理集群。是業界第一個多集群多云管理平臺。正如發布而極大地幫助普及了技術一樣,我們也相信將促進將多集群多云管理帶入更主流的階段。 今天, Google Cloud NEXT 2019大會召開,在這場規模三萬人的盛會上,G...
摘要:梳理之后,目標就會被分解成一個個需要完成的具體任務。勤學學習效率與效果取決于執行力。這種選手即便幫他解決了問題,他也學不到東西。拆分任務將目標分解成具體可執行的學習任務。搜集知識資源查閱官方文檔購買書籍搜集網絡干貨文章。 前段時間和大家一起分享了一篇關于學習方法內容《大牛與搬運工的差距——學習方法的力量》。我們將學習過程分成八步,并借鑒了敏捷開發的迭代思想,以達到自我迭代學習的效果。行...
摘要:每個任務必須顯式地掛起自己,在任務切換發生時給予它完全的控制。在這些嘗試中,數據經常在任務之間共享。但由于明確的暫停,幾乎沒有風險。 翻譯自 github 概述 什么是generators? 我們可以把generators理解成一段可以暫停并重新開始執行的函數 function* genFunc() { // (A) console.log(First); yi...
摘要:要說與是如何協同工作的,首先得說和這兩個協議。是與后臺語言交互的協議,有了這個協議,開發者可以使用任何語言處理發來的請求,動態的生成內容。為了能夠使理解協議,提供了模塊來將請求映射為對應的請求。如此以來,與通信的整個流程應該比較清晰了吧。 【原文地址】https://zhuanlan.zhihu.com/p/... 網絡上有很多關于如何配置 Nginx + FPM 的文章,但它們更多從...
閱讀 3454·2023-04-25 19:39
閱讀 3801·2021-11-18 13:12
閱讀 3635·2021-09-22 15:45
閱讀 2434·2021-09-22 15:32
閱讀 718·2021-09-04 16:40
閱讀 3729·2019-08-30 14:11
閱讀 1884·2019-08-30 13:46
閱讀 1566·2019-08-29 15:43