摘要:的返回值是傳遞給方法的值。上面的例子演示了基本用法,然而上下文中沒(méi)有真正的展示出使用協(xié)程的優(yōu)點(diǎn)。這個(gè)時(shí)候你應(yīng)當(dāng)明白協(xié)程和任務(wù)調(diào)度之間的聯(lián)系指令提供了任務(wù)中斷自身的一種方法,然后把控制傳遞給調(diào)度器。因此協(xié)程可以運(yùn)行多個(gè)其他任務(wù)。
協(xié)程是比較少見(jiàn)的概念,先轉(zhuǎn)過(guò)來(lái)作為參考,需要時(shí)應(yīng)該可以用到
轉(zhuǎn)自:http://www.oschina.net/transl...
生成器最基本的思想也是一個(gè)函數(shù),這個(gè)函數(shù)的返回值是依次輸出,而不是只返回一個(gè)多帶帶的值?;蛘撸瑩Q句話(huà)說(shuō),生成器使你更方便的實(shí)現(xiàn)了迭代器接口。下面通過(guò)實(shí)現(xiàn)一個(gè)xrange函數(shù)來(lái)簡(jiǎn)單說(shuō)明:
上面這個(gè)xrange()函數(shù)提供了和PHP的內(nèi)建函數(shù)range()一樣的功能。但是不同的是range()函數(shù)返回的是一個(gè)包含屬組值從1到100萬(wàn)的數(shù)組(注:請(qǐng)查看手冊(cè))。而xrange()函數(shù)返回的是依次輸出這些值的一個(gè)迭代器,而且并不會(huì)真正以數(shù)組形式計(jì)算。
這種方法的優(yōu)點(diǎn)是顯而易見(jiàn)的。它可以讓你在處理大數(shù)據(jù)集合的時(shí)候不用一次性的加載到內(nèi)存中。甚至你可以處理無(wú)限大的數(shù)據(jù)流。
當(dāng)然,也可以不同通過(guò)生成器來(lái)實(shí)現(xiàn)這個(gè)功能,而是可以通過(guò)繼承Iterator接口實(shí)現(xiàn)。通過(guò)使用生成器實(shí)現(xiàn)起來(lái)會(huì)更方便,而不用再去實(shí)現(xiàn)iterator接口中的5個(gè)方法了。
生成器為可中斷的函數(shù)要從生成器認(rèn)識(shí)協(xié)同程序,理解它們內(nèi)部是如何工作的非常重要:生成器是可中斷的函數(shù),在它里面,yield構(gòu)成了中斷點(diǎn)。?
緊接著上面的例子,如果你調(diào)用xrange(1,1000000)的話(huà),xrange()函數(shù)里代碼沒(méi)有真正地運(yùn)行。相反,PHP只是返回了一個(gè)實(shí)現(xiàn)了迭代器接口的 生成器類(lèi)實(shí)例:?
?
?
?
協(xié)程
協(xié)程給上面功能添加的主要東西是回送數(shù)據(jù)給生成器的能力。這將把生成器到調(diào)用者的單向通信轉(zhuǎn)變?yōu)閮烧咧g的雙向通信。
?
send("Foo"); $logger->send("Bar")正如你能看到,這兒yield沒(méi)有作為一個(gè)語(yǔ)句來(lái)使用,而是用作一個(gè)表達(dá)式。即它有一個(gè)返回值。yield的返回值是傳遞給send()方法的值。 在這個(gè)例子里,yield將首先返回"Foo",然后返回"Bar"。
上面的例子里yield僅作為接收者。混合兩種用法是可能的,即既可接收也可發(fā)送。接收和發(fā)送通信如何進(jìn)行的例子如下:
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())多任務(wù)協(xié)作
如果閱讀了上面的logger()例子,那么你認(rèn)為“為了雙向通信我為什么要使用協(xié)程呢? 為什么我不能只用常見(jiàn)的類(lèi)呢?”,你這么問(wèn)完全正確。上面的例子演示了基本用法,然而上下文中沒(méi)有真正的展示出使用協(xié)程的優(yōu)點(diǎn)。這就是列舉許多協(xié)程例子的理由。正如上面介紹里提到的,協(xié)程是非常強(qiáng)大的概念,不過(guò)這樣的應(yīng)用很稀少而且常常十分復(fù)雜。給出一些簡(jiǎn)單而真實(shí)的例子很難。
多任務(wù)協(xié)作這個(gè)術(shù)語(yǔ)中的“協(xié)作”說(shuō)明了如何進(jìn)行這種切換的:它要求當(dāng)前正在運(yùn)行的任務(wù)自動(dòng)把控制傳回給調(diào)度器,這樣它就可以運(yùn)行其他任務(wù)了。這與“搶占”多任務(wù)相反,搶占多任務(wù)是這樣的:調(diào)度器可以中斷運(yùn)行了一段時(shí)間的任務(wù),不管它喜歡還是不喜歡。協(xié)作多任務(wù)在Windows的早期版本(windows95)和Mac OS中有使用,不過(guò)它們后來(lái)都切換到使用搶先多任務(wù)了。理由相當(dāng)明確:如果你依靠程序自動(dòng)傳回 控制的話(huà),那么壞行為的軟件將很容易為自身占用整個(gè)CPU,不與其他任務(wù)共享。?
這個(gè)時(shí)候你應(yīng)當(dāng)明白協(xié)程和任務(wù)調(diào)度之間的聯(lián)系:yield指令提供了任務(wù)中斷自身的一種方法,然后把控制傳遞給調(diào)度器。因此協(xié)程可以運(yùn)行多個(gè)其他任務(wù)。更進(jìn)一步來(lái)說(shuō),yield可以用來(lái)在任務(wù)和調(diào)度器之間進(jìn)行通信。
我們的目的是 對(duì) “任務(wù)”用更輕量級(jí)的包裝的協(xié)程函數(shù):
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(); } }?
任務(wù)ID標(biāo)記
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!調(diào)度器現(xiàn)在不得不比多任務(wù)循環(huán)要做稍微多點(diǎn)了,然后才運(yùn)行多任務(wù):
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.與調(diào)度器之間通信?既然調(diào)度器已經(jīng)運(yùn)行了,那么我們就轉(zhuǎn)向日程表的下一項(xiàng):任務(wù)和調(diào)度器之間的通信。我們將使用進(jìn)程用來(lái)和操作系統(tǒng)會(huì)話(huà)的同樣的方式來(lái)通信:系統(tǒng)調(diào)用。我們需要系統(tǒng)調(diào)用的理由是操作系統(tǒng)與進(jìn)程相比它處在不同的權(quán)限級(jí)別上。因此為了執(zhí)行特權(quán)級(jí)別的操作(如殺死另一個(gè)進(jìn)程),就不得不以某種方式把控制傳回給內(nèi)核,這樣內(nèi)核就可以執(zhí)行所說(shuō)的操作了。再說(shuō)一遍,這種行為在內(nèi)部是通過(guò)使用中斷指令來(lái)實(shí)現(xiàn)的。過(guò)去使用的是通用的int指令,如今使用的是更特殊并且更快速的syscall/sysenter指令。
為了說(shuō)明系統(tǒng)調(diào)用,我將對(duì)可調(diào)用的系統(tǒng)調(diào)用做一個(gè)小小的封裝:
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函數(shù)需要在調(diào)度器里增加一個(gè)方法:
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.
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/30562.html
摘要:今天,大會(huì)召開(kāi),在這場(chǎng)規(guī)模三萬(wàn)人的盛會(huì)上,宣布推出作為多云服務(wù)新方案,提供跨云目前僅支持和管理集群。是業(yè)界第一個(gè)多集群多云管理平臺(tái)。正如發(fā)布而極大地幫助普及了技術(shù)一樣,我們也相信將促進(jìn)將多集群多云管理帶入更主流的階段。 今天, Google Cloud NEXT 2019大會(huì)召開(kāi),在這場(chǎng)規(guī)模三萬(wàn)人的盛會(huì)上,G...
摘要:梳理之后,目標(biāo)就會(huì)被分解成一個(gè)個(gè)需要完成的具體任務(wù)。勤學(xué)學(xué)習(xí)效率與效果取決于執(zhí)行力。這種選手即便幫他解決了問(wèn)題,他也學(xué)不到東西。拆分任務(wù)將目標(biāo)分解成具體可執(zhí)行的學(xué)習(xí)任務(wù)。搜集知識(shí)資源查閱官方文檔購(gòu)買(mǎi)書(shū)籍搜集網(wǎng)絡(luò)干貨文章。 前段時(shí)間和大家一起分享了一篇關(guān)于學(xué)習(xí)方法內(nèi)容《大牛與搬運(yùn)工的差距——學(xué)習(xí)方法的力量》。我們將學(xué)習(xí)過(guò)程分成八步,并借鑒了敏捷開(kāi)發(fā)的迭代思想,以達(dá)到自我迭代學(xué)習(xí)的效果。行...
摘要:每個(gè)任務(wù)必須顯式地掛起自己,在任務(wù)切換發(fā)生時(shí)給予它完全的控制。在這些嘗試中,數(shù)據(jù)經(jīng)常在任務(wù)之間共享。但由于明確的暫停,幾乎沒(méi)有風(fēng)險(xiǎn)。 翻譯自 github 概述 什么是generators? 我們可以把generators理解成一段可以暫停并重新開(kāi)始執(zhí)行的函數(shù) function* genFunc() { // (A) console.log(First); yi...
摘要:要說(shuō)與是如何協(xié)同工作的,首先得說(shuō)和這兩個(gè)協(xié)議。是與后臺(tái)語(yǔ)言交互的協(xié)議,有了這個(gè)協(xié)議,開(kāi)發(fā)者可以使用任何語(yǔ)言處理發(fā)來(lái)的請(qǐng)求,動(dòng)態(tài)的生成內(nèi)容。為了能夠使理解協(xié)議,提供了模塊來(lái)將請(qǐng)求映射為對(duì)應(yīng)的請(qǐng)求。如此以來(lái),與通信的整個(gè)流程應(yīng)該比較清晰了吧。 【原文地址】https://zhuanlan.zhihu.com/p/... 網(wǎng)絡(luò)上有很多關(guān)于如何配置 Nginx + FPM 的文章,但它們更多從...
閱讀 3621·2023-04-25 19:39
閱讀 3966·2021-11-18 13:12
閱讀 3750·2021-09-22 15:45
閱讀 2557·2021-09-22 15:32
閱讀 909·2021-09-04 16:40
閱讀 4027·2019-08-30 14:11
閱讀 2008·2019-08-30 13:46
閱讀 1699·2019-08-29 15:43