<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                # 2.3 協程原理 ## 協程 ### 基本概念 “協程”(Coroutine)概念最早由 Melvin Conway 于1958年提出。協程可以理解為純用戶態的線程,其通過協作而不是搶占來進行切換。相對于進程或者線程,協程所有的操作都可以在用戶態完成,創建和切換的消耗更低。總的來說,協程為協同任務提供了一種運行時抽象,這種抽象非常適合于協同多任務調度和數據流處理。在現代操作系統和編程語言中,因為用戶態線程切換代價比內核態線程小,協程成為了一種輕量級的多任務模型。 從編程角度上看,協程的思想本質上就是控制流的主動讓出(yield)和恢復(resume)機制,迭代器常被用來實現協程,所以大部分的語言實現的協程中都有yield關鍵字,比如Python、PHP、Lua。但也有特殊比如Go就使用的是通道來通信。 ### 協程與進程線程的區別 * 對于操作系統來說只有進程和線程,協程的控制由應用程序顯式調度,非搶占式的 * 協程的執行最終靠的還是線程,應用程序來調度協程選擇合適的線程來獲取執行權 * 切換非常快,成本低。一般占用棧大小遠小于線程(協程KB級別,線程MB級別),所以可以開更多的協程 * 協程比線程更輕量級 ### PHP與協程 PHP從5.5引入了yield關鍵字,增加了迭代生成器和協程的支持,但并未在語言本身級別實現一個完善的協程解決方案。PHP協程也是基于Generator,Generator可以視為一種“可中斷”的函數,而 yield 構成了一系列的“中斷點”。PHP 協程沒有resume關鍵字,而是“在使用的時候喚起”協程。了解如何在PHP中實現協程,首先要解決迭代生成器。 ```php function xrange($start, $end, $step = 1) { for ($i = $start; $i <= $end; $i += $step) { yield $i; } } foreach (xrange(1, 1000000) as $num) { // xrange返回的是一個Generator對象 echo $num, "\n"; } ``` 具體參考 [PHP > 手冊 > 語言參考 > 生成器](http://php.net/manual/zh/language.generators.overview.php) ### 中斷點 我們從生成器認識協程,需要認識到:生成器是一種具有中斷點的函數,而yield構成了中斷點。比如, 你調用$range->rewind(),那么xrange()里的代碼就會運行到控制流第一次出現yield的地方,而函數內傳遞給yield語句的值,即為迭代的當前值,可以通過$xrange->current()獲取。 ### PHP中的協程實現 PHP的協程支持是在迭代生成器的基礎上,增加了可以回送數據給生成器的功能,從而達到雙向通信即: 生成器<---數據--->調用者 #### yield接收與發送數據 ```php function gen() { $ret = (yield 'yield1'); var_dump($ret); $ret = (yield 'yield2'); var_dump($ret); } $gen = gen(); var_dump($gen->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()) ``` ```php function gen() { yield 'foo'; yield 'bar'; } $gen = gen(); var_dump($gen->send('something')); // 在send之前當$gen迭代器被創建的時候一個renwind()方法已經被隱式調用 // 所以實際上發生的應該類似: //$gen->rewind(); //var_dump($gen->send('something')); //這樣renwind的執行將會導致第一個yield被執行, 并且忽略了他的返回值. //真正當我們調用yield的時候, 我們得到的是第二個yield的值! 導致第一個yield的值被忽略. //string(3) "bar" ``` #### 協程與任務調度 yield指令提供了任務中斷自身的一種方法,然后把控制交回給任務調度器。而PHP語言本身只是提供程序中斷的功能,至于任務調度器需要我們自己實現,同時協程在運行多個其他任務時,yield還可以用來在任務和調度器之間進行通信。 #### PHP協程任務 簡單的定義具有任何ID標識的協程函數,如一個輕量級的協程函數示例代碼: ```php <?php class Task { protected $taskId; protected $coroutine; protected $sendValue = null; protected $beforeFirstYield = true; public function __construct($taskId, Generator $coroutine) { $this->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(); } } ``` #### PHP協程調度器 簡單來說,是可以在多個任務之間相互協調,及任務之間相互切換的一種進程資源的分配器。調度器的實現方式有多種,大致分為兩類:一是,隊列;二是,定時器。 ```php class Scheduler { protected $maxTaskId = 0; protected $taskMap = []; // taskId => 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()方法創建一個新任務,然后把這個任務放入任務map數組里,接著它通過把任務放入任務隊列里來實現對任務的調度。接著run()方法掃描任務隊列,運行任務,如果一個任務結束了,那么它將從隊列里刪除,否則它將在隊列的末尾再次被調度。 協程示例: ```php function task1() { for ($i = 1; $i <= 10; ++$i) { echo "This is task 1 iteration $i.\n"; yield; } } function task2() { for ($i = 1; $i <= 5; ++$i) { echo "This is task 2 iteration $i.\n"; yield; } } $scheduler = new Scheduler; $scheduler->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. ```
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看