PHP進階教程-PHP的協程怎麼玩?這一篇帶你搞定swoole協程

協程說複雜不復雜說難也不難,一句話能夠歸納:能提升併發,但不能加速任務,同步代碼實現異步IO,異步非阻塞的代碼塊。php

協程是一種特殊函數,是一種能夠掛起的函數,而後能夠從掛起的地方從新恢復執行,一個線程內的多個協程是串行的,跟CPU處理進程同樣,同一時刻只能一個協程在線程上運行,除非出讓了控制權給別的協程運行。協程沒法利用多核CPU所以協程只能解決併發問題,不能解決任務處理速度問題。協程就是把一個大任務再分紅更小的片斷,封裝程一個函數,當其中一個協程須要IO阻塞的時候,主動掛起當前協程,把控制權交給其餘協程運行。laravel

咱們知道進程和線程是由操做系統調度的,何時執行取決於操做系統何時把CPU時間交給某個進程或者線程,而協程是何時交出控制權是由用戶決定的。進程和線程屬於內核態,協程屬於用戶態線程。sql

協程是一種用戶態的輕量級線程,協程的調度徹底由用戶控制。協程擁有本身的寄存器上下文和棧。協程調度切換時,將寄存器上下文和棧保存到其餘地方,在切回來的時候,恢復先前保存的寄存器上下文和棧,直接操做棧則基本沒有內核切換的開銷,能夠不加鎖的訪問全局變量,因此上下文的切換很是快。shell

個人 企鵝羣 一塊兒交流哦服務器

協程特色

  • 用戶態線程、遇到IO主動讓出控制權swoole

  • 多個協程代碼依然是串行的,無需加鎖網絡

  • 開銷低,只佔用內存,不存在進程、線程切換開銷架構

  • 併發量大,單個進程可開啓50w個協程併發

  • 隨時隨地,只要想併發,就調用go建立協程異步

在這裏插入圖片描述

咱們知道線程是輕量級的進程,那麼協程就是輕量級的線程。協程運行在線程之上,一個線程能夠有多個協程。

咱們知道在進程遇到阻塞的時候開多一個線程在進程內部切換,避免每次都切換進程,這樣能夠更大力度的使用CPU分給這個進程的可以使用時間。而協程跟線程和進程的關係很相似,只不過協程是跟線程直接創建關係。

在這裏插入圖片描述

上圖是多個線程之間切換的示意圖,那麼咱們來考慮一下,若是線程只是等待IO操做(網絡或者文件),那麼爲何像線程重複使用進程同樣來重複的使用這個線程呢?咱們把IO去掉,看看這個圖是什麼樣子的。

在這裏插入圖片描述

去掉IO部分操做,能夠看出來基本上這個併發請求應用程序代碼能夠在 單個線程中 運行,協程最大力度的利用了線程等待IO的時間,讓程序在等待IO的時候能夠執行別的業務代碼。

在這裏插入圖片描述

看着像不像一個線程的執行流程,這就是協程的魅力所在,當一個協程被yield以後會被掛起,把控制權轉移給線程內部的其餘協程,由於是在線程上進行的切換,因此開銷遠遠比進程和線程低不少。

在這裏插入圖片描述

當程序調用協程以後,當前協程會主動讓出控制權交給同一個線程內的其餘協程處理,如圖所示,開發者代碼中須要使用IO的時候主動讓出協程的控制權給別的協程使用。

在這裏插入圖片描述

去掉IO部分再看協程的處理,直接執行的都是業務邏輯,避免遇到IO致使線程轉換到等待狀態,更充分的利用CPU分給這個線程的執行時間。

注意:協程並不能讓任務加速進行,只能執行更多任務。

協程因爲是創建在線程之上的,所以沒有辦法使用CPU多核心的優點,協程適合適用於IO密集運算的場景。

協程有什麼做用?

協程是爲了提升CPU使用率,避免在線程阻塞的時候大量的線程上下文切換。

echo "1-start\n";
sleep(1);
echo "1-end\n";
echo "2-start\n";
sleep(1);
echo "2-end\n";
echo "3-start\n";
sleep(1);
echo "3-end\n";
echo "4-start\n";
sleep(1);
echo "4-end\n";

在這裏插入圖片描述

以上代碼的CPU使用率僅有 1%

Swoole\Runtime::enableCoroutine(true);
go(function () {
    echo "go1-start\n";
    sleep(1);
    echo "go1-end\n";
});
go(function () {
    echo "go2-start\n";
    sleep(1);
    echo "go2-end\n";
});
go(function () {
    echo "go3-start\n";
    sleep(1);
    echo "go3-end\n";
});
go(function () {
    echo "go4-start\n";
    sleep(1);
    echo "go4-end\n";
});

在這裏插入圖片描述

使用協程,成功把CPU使用率提升到了4%,這樣CPU就不須要爲了IO阻塞而空跑,或者進行上下文切換。以前不是說過協程不能加速嗎?這裏使用協程以後怎麼1秒多就執行完了,跟前面的代碼不同?這裏獲得的時間取決於最後一個協程執行結束的時間。

協程的執行順序

Swoole\Runtime::enableCoroutine(true);
go(function(){
   sleep(2);
   echo "go1\n";
});
go(function(){
    sleep(1);
    echo "go2\n";
});
echo "main\n";

先輸出:main->go2->go1

協程之間通信

多個協程之間通信,採用Channel實現,多個協程協助完成共同的任務。

Swoole\Runtime::enableCoroutine(true);
$chan = new Swoole\Coroutine\Channel();
go(function () use ($chan){
    sleep(1);
    $chan->push(['name'=>'sunny']);
});

go(function() use ($chan){
    $data = $chan->pop();
    print_r($data);
});
echo "結束\n";

實戰:實現waitGroup功能

利用Swoole提供的Channel實現一個 waitGroup ,主要功能是用來等待全部協程執行完成的。

<?php
class WaitGroup{
    private $count;
    private $chan;
    public function __construct()
{
        $this->chan = new Swoole\Coroutine\Channel();
    }

    public function add(){
        $this->count++;
    }
    public function done(){
        $this->chan->push(true);
    }

    public function wait(){
        for($i=0;$i<$this->count;$i++){
            $this->chan->pop();
        }
    }

}

<?php
include 'waitgroup.php';
Swoole\Runtime::enableCoroutine(true);
echo "start".PHP_EOL;
$t = microtime(true);
go(function() use ($t){
    $wg = new WaitGroup();
    $wg->add();
    go(function() use ($t,&$wg){
        echo file_get_contents("https://www.sunnyos.com/swoole.php");
        echo "協程1:".(microtime(true)-$t).PHP_EOL;
        $wg->done();
    });
    $wg->add();
    go(function() use ($t,&$wg){
        echo file_get_contents("https://www.sunnyos.com/swoole.php");
        echo "協程2:".(microtime(true)-$t).PHP_EOL;
        $wg->done();
    });
    $wg->add();
    go(function() use ($t,&$wg){
        echo file_get_contents("https://www.sunnyos.com/swoole.php");
        echo "協程3:".(microtime(true)-$t).PHP_EOL;
        $wg->done();
    });
    $wg->wait();
    echo '所有結束:'.(microtime(true)-$t).PHP_EOL;
});
echo "end".PHP_EOL;
echo microtime(true)-$t.PHP_EOL;

代碼中:https://www.sunnyos.com/swoole.php swoole.php 的代碼

<?php
sleep(1);
echo "My name is Sunny\n";

休眠疫苗模擬網絡請求耗時

在這裏插入圖片描述

這裏看看使用協程3個協程都進行了網絡請求,每一個請求耗時1秒,可是在這裏執行都時候三個請求執行完了僅耗時1.2秒,可是cpu都使用率卻使用到了6%,這說明了協程充分的使用了cpu。

點關注,不迷路

好了各位,以上就是這篇文章的所有內容了,能看到這裏的人呀,都是人才。以前說過,PHP方面的技術點不少,也是由於太多了,實在是寫不過來,寫過來了你們也不會看的太多,因此我這裏把它整理成了PDF和文檔,若是有須要的能夠

點擊進入暗號: PHP+「平臺」

在這裏插入圖片描述

在這裏插入圖片描述


更多學習內容能夠訪問【對標大廠】精品PHP架構師教程目錄大全,只要你能看完保證薪資上升一個臺階(持續更新)

以上內容但願幫助到你們,不少PHPer在進階的時候總會遇到一些問題和瓶頸,業務代碼寫多了沒有方向感,不知道該從那裏入手去提高,對此我整理了一些資料,包括但不限於:分佈式架構、高可擴展、高性能、高併發、服務器性能調優、TP6,laravel,YII2,Redis,Swoole、Swoft、Kafka、Mysql優化、shell腳本、Docker、微服務、Nginx等多個知識點高級進階乾貨須要的能夠免費分享給你們,須要的能夠加入個人 PHP技術交流羣

相關文章
相關標籤/搜索