<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          協(xié)程編程注意事項(xiàng)

          共 3844字,需瀏覽 8分鐘

           ·

          2022-01-24 00:38

          1.協(xié)程內(nèi)部禁止使用全局變量,以免發(fā)生數(shù)據(jù)錯(cuò)亂;(非多協(xié)程協(xié)作場(chǎng)景)

          原因:協(xié)程是共享進(jìn)程資源的,也就是全局變量共享,用來(lái)處理任務(wù)時(shí),全局變量很容易被別的協(xié)程篡改,導(dǎo)致數(shù)據(jù)錯(cuò)亂。


          2.協(xié)程使用?use?關(guān)鍵字引入外部變量到當(dāng)前作用域禁止使用引用,以免發(fā)生數(shù)據(jù)錯(cuò)亂;

          (非多協(xié)程協(xié)作場(chǎng)景)

          原因:引用是原變量的真實(shí)地址,由于協(xié)程是共享進(jìn)程資源的,會(huì)導(dǎo)致原變量很容易被別的協(xié)程篡改,導(dǎo)致數(shù)據(jù)錯(cuò)亂。


          3.不能使用 ?(非多協(xié)程協(xié)作場(chǎng)景)

          (1)類靜態(tài)變量?Class::$array?

          (2)全局變量?$_array?

          (3)全局對(duì)象屬性?$object->array

          (4)其他超全局變量$GLOBALS ? 等保存協(xié)程上下文內(nèi)容,以免發(fā)生數(shù)據(jù)錯(cuò)亂;

          上下文Context類實(shí)際上采用標(biāo)記協(xié)程id的方式來(lái)分發(fā)存儲(chǔ)各個(gè)協(xié)程對(duì)應(yīng)的數(shù)據(jù)資源(數(shù)據(jù)池):


          use Swoole\Coroutine;class Context{   protected static $pool = []; //進(jìn)程創(chuàng)建后此靜態(tài)變量就會(huì)存在,但只會(huì)根據(jù)對(duì)應(yīng)的id去覆蓋對(duì)應(yīng)協(xié)程下的數(shù)據(jù)     // 基于協(xié)程 `ID` 獲取數(shù)據(jù)    static function get($key){        $cid = Coroutine::getCid();        if ($cid < 0)        {            return null;        }        if(isset(self::$pool[$cid][$key])){            return self::$pool[$cid][$key];        }        return null;    }     // 基于協(xié)程 `ID` 寫入數(shù)據(jù)    static function put($key, $item){        $cid = Coroutine::getCid();        if ($cid > 0)        {            self::$pool[$cid][$key] = $item;        }     }     // 基于協(xié)程 `ID` 刪除數(shù)據(jù)    static function delete($key = null){        $cid = Coroutine::getCid();        if ($cid > 0)        {            if($key){                unset(self::$pool[$cid][$key]);            }else{                unset(self::$pool[$cid]);            }        }    }}

          4.協(xié)程之間通訊必須使用通道(Channel)場(chǎng)景:如果需要使用多協(xié)程協(xié)作執(zhí)行任務(wù)時(shí)

          Coroutine\Channel?使用本地內(nèi)存,不同的進(jìn)程之間內(nèi)存是隔離的。

          只能在同一進(jìn)程的不同協(xié)程內(nèi)進(jìn)行?push?和?pop?操作。

          不過(guò)理論上仍然有共享內(nèi)存的方式,只是需要進(jìn)行上鎖,保持同步機(jī)制


          5.不能在多個(gè)協(xié)程間共用一個(gè)客戶端連接,以免發(fā)生數(shù)據(jù)錯(cuò)亂;可以使用連接池實(shí)現(xiàn);

          原因:同樣是因?yàn)檫B接標(biāo)識(shí)共享,有可能前腳一個(gè)協(xié)程剛對(duì)鏈接做了操作,后腳被別的協(xié)程改了數(shù)據(jù)。(非多協(xié)程協(xié)作場(chǎng)景)

          $pool = new RedisPool();$server = new Swoole\Http\Server('127.0.0.1', 9501);$server->set([    // 如開(kāi)啟異步安全重啟, 需要在workerExit釋放連接池資源    'reload_async' => true]);$server->on('start', function (swoole_http_server $server) {    var_dump($server->master_pid);});$server->on('workerExit', function (swoole_http_server $server) use ($pool) {    $pool->destruct();});$server->on('request', function (swoole_http_request $req, swoole_http_response $resp) use ($pool) {    //從連接池中獲取一個(gè)Redis協(xié)程客戶端    $redis = $pool->get();    //連接失敗    if ($redis === false) {        $resp->end("ERROR");        return;    }    $result = $redis->hgetall('key');    $resp->end(var_export($result, true));    //釋放客戶端,其他協(xié)程可復(fù)用此對(duì)象    $pool->put($redis);});$server->start();
          class RedisPool{ protected $available = true; protected $pool;
          public function __construct(){ $this->pool = new SplQueue; }
          public function put($redis){ $this->pool->push($redis); }
          /** * @return bool|mixed|\Swoole\Coroutine\Redis */ public function get(){ //有空閑連接且連接池處于可用狀態(tài) if ($this->available && count($this->pool) > 0) { return $this->pool->pop(); }
          //無(wú)空閑連接,創(chuàng)建新連接 $redis = new Swoole\Coroutine\Redis(); $res = $redis->connect('127.0.0.1', 6379); if ($res == false) { return false; } else { return $redis; } }
          public function destruct(){ // 連接池銷毀, 置不可用狀態(tài), 防止新的客戶端進(jìn)入常駐連接池, 導(dǎo)致服務(wù)器無(wú)法平滑退出 $this->available = false; while (!$this->pool->isEmpty()) { $this->pool->pop(); } }}
          6.在 Swoole\Server 中,客戶端連接應(yīng)當(dāng)在 onWorkerStart 中創(chuàng)建;

          原因:使得客戶端鏈接在整個(gè)進(jìn)程周期中可用。


          7.在 Swoole\Process 中,客戶端連接應(yīng)當(dāng)在 Swoole\Process->start 后,子進(jìn)程的回調(diào)函數(shù)中創(chuàng)建;

          原因:使得客戶端鏈接在整個(gè)子進(jìn)程周期中可用。


          8.必須在協(xié)程內(nèi)捕獲異常,不得跨協(xié)程捕獲異常;

          原因:多協(xié)程下,try/catchthrow在不同的協(xié)程中,協(xié)程內(nèi)無(wú)法捕獲到此異常。當(dāng)協(xié)程退出時(shí),發(fā)現(xiàn)有未捕獲的異常,將引起致命錯(cuò)誤。

          錯(cuò)誤:try {    Swoole\Coroutine::create(function () {        throw new \RuntimeException(__FILE__, __LINE__);    });}catch (\Throwable $e) {    echo $e;}#try/catch和throw在不同的協(xié)程中,協(xié)程內(nèi)無(wú)法捕獲到此異常。當(dāng)協(xié)程退出時(shí),發(fā)現(xiàn)有未捕獲的異常,將引起致命錯(cuò)誤。
          正解:function test() { throw new \RuntimeException(__FILE__, __LINE__);}Swoole\Coroutine::create(function () { try { test(); } catch (\Throwable $e) { echo $e; }});

          9.在__get /__set魔術(shù)方法中不能有協(xié)程切換。(跟php本身有關(guān))


          瀏覽 39
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  无码v| 妻AV在线 | 特一级A片视频 | v天堂在线 | 黄片视频在线免费看 |