91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何通過swoole協程實現并發編程

發布時間:2021-11-15 15:39:29 來源:億速云 閱讀:320 作者:柒染 欄目:大數據

這篇文章給大家介紹如何通過swoole協程實現并發編程,內容非常詳細,感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。

目前的Swoole 內置了豐富的協程組件供開發者直接調用以便快速實現異步非阻塞的并發編程,省去了開發者自己實現相應底層代碼的麻煩:

TCP/UDP Client:Swoole\Coroutine\Client
TCP/UDP Server:Swoole\Coroutine\Server
HTTP/WebSocket Client:Swoole\Coroutine\HTTP\Client
HTTP/WebSocket Server:Swoole\Coroutine\HTTP\Server
HTTP2 Client:Swoole\Coroutine\HTTP2\Client
Redis Client:Swoole\Coroutine\Redis
Mysql Client:Swoole\Coroutine\MySQL
PostgreSQL Client:Swoole\Coroutine\PostgreSQL

在協程 Server 中使用對應的協程版 Client 來實現全異步 Server,同時 Swoole 提供了協程工具集:Swoole\Coroutine,提供了獲取當前協程ID、反射調用等能力。

通過 setDefer 機制實現并發編程

我們以 Redis 和 MySQL 客戶端請求為例,使用上述 Swoole\Coroutine\Redis 和 Swoole\Coroutine\MySQL 組件,可以實現異步 Redis 和 MySQL 客戶端:

<?php$server = new \Swoole\Http\Server('127.0.0.1', 9588);$server->on('Request', function ($request, $response) {var_dump(time());$mysql = new Swoole\Coroutine\MySQL();$mysql->connect(['host' => '127.0.0.1','user' => 'root','password' => 'root','database' => 'laravel58',]);$mysql->setDefer();$mysql->query('select sleep(3)');var_dump(time());$redis1 = new Swoole\Coroutine\Redis();$redis1->connect('127.0.0.1', 6379);$redis1->setDefer();$redis1->set('hello', 'world');var_dump(time());$redis2 = new Swoole\Coroutine\Redis();$redis2->connect('127.0.0.1', 6379);$redis2->setDefer();$redis2->get('hello');$result1 = $mysql->recv();$result2 = $redis2->recv();var_dump($result1, $result2, time());$response->end('Request Finish: ' . time());});$server->start();

由于 Swoole 會在 TCP Server 和 HTTP Server 回調函數中會自動開啟協程,所以不需要顯式通過 go 關鍵字啟動協程,然后我們可以在回調函數中使用 MySQL 和 Redis 客戶端協程組件發起請求。

要理解上述代碼的運行原理,需要先了解協程的 setDefer 機制,絕大部分協程組件都支持 setDefer,該機制可以將請求響應式的接口拆分為兩個步驟:先發送數據, 再并發收取響應結果。

由于大多數情況下,「建立連接和發送數據的耗時」相較于「等待響應的耗時」來說可以忽略不計, 所以可以簡單理解為 defer 模式下, 多個客戶端的請求響應是并發的(實際上只有接收響應是并發的,建立連接和發送請求是串行的)。

以上述代碼為例,設置 setDefer(true) 后,通過 Redis 或 MySQL 客戶端發起請求,將不再等待服務器返回結果,而是在發送請求之后,立即返回 true。在此之后可以繼續發起其他 Redis、MySQL 請求,最后再使用 recv() 方法接收響應內容。

我們將上述代碼保存到 coroutine/http.php,然后在終端啟動這個 HTTP 服務端:

php coroutine/http.php

接下來,在 Postman 中對服務端發起請求,會在等待幾秒后看到返回的響應內容:

如何通過swoole協程實現并發編程

前三個時間分別是 mysqlredis1redis2 三個客戶端發起請求的時間,可以看到,盡管 mysql 中會休眠 3 秒,但是通過 defer 機制實現了三個請求的并發執行。

通過子協程+通道實現并發編程

除了 setDefer 機制外,Swoole 還支持通過子協程+通道實現并發編程,下面我們通過子協程+通道的方式來改寫上面的代碼實現:

<?php$server = new \Swoole\Http\Server('127.0.0.1', 9588);$server->on('Request', function ($request, $response) {$channel = new \Swoole\Coroutine\Channel(3);go(function () use ($channel) {var_dump(time());$mysql = new Swoole\Coroutine\MySQL();$mysql->connect(['host' => '127.0.0.1','user' => 'root','password' => 'root','database' => 'laravel58',]);$result = $mysql->query('select sleep(3)');$channel->push($result);});go(function () use ($channel) {var_dump(time());$redis1 = new Swoole\Coroutine\Redis();$redis1->connect('127.0.0.1', 6379);$result = $redis1->set('hello', 'world');$channel->push($result);});go(function () use ($channel) {var_dump(time());$redis2 = new Swoole\Coroutine\Redis();$redis2->connect('127.0.0.1', 6379);$result = $redis2->get('hello');$channel->push($result);});$results = [];for ($i = 0; $i < 3; $i++) {$results[] = $channel->pop();}$response->end(json_encode(['data' => $results,'time' => time()]));});$server->start();

我們將 MySQL 和 Redis 客戶端連接請求調用改寫為通過三個子協程實現,同時去掉 setDefer 設置,因為這三個子協程已經是并發調用了,此外,由于三個子協程之間數據是相互隔離的,所以我們通過 Swoole\Coroutine\Channel (即通道)實現協程之間的數據共享和通信,初始化其緩沖空間為 3,然后通過 use 方式將其引入到子協程中,把響應結果通過 push 方法放到 Channel 里面,接下來在服務端 onRequest 回調函數末尾通過一個循環將 Channel 中的數據通過 pop 方法依次取出來放到數組 $results 中,最后通過 $response->end() 方法將結果以 JSON 格式返回給客戶端。

我們將上述代碼保存到 coroutine/http2.php,然后在終端通過如下命令啟動這個新的 HTTP 服務端:

php coroutine/http2.php

還是在 Postman 中請求這個服務端,將響應格式調整為 JSON,會看到結果如下:

如何通過swoole協程實現并發編程

由于 MySQL 請求執行耗時最長,所以位置最靠后。在啟動服務器的終端,可以看到打印出的三個客戶端請求時間,完全一致,說明它們是并發執行的:

如何通過swoole協程實現并發編程

顯然,通過子協程 + 通道還可以很方便的實現 Redis、MySQL 連接池。

關于如何通過swoole協程實現并發編程就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

巴东县| 布拖县| 兴业县| 右玉县| 梨树县| 辽宁省| 乐亭县| 新源县| 礼泉县| 额尔古纳市| 大庆市| 崇信县| 涟水县| 驻马店市| 育儿| 大理市| 环江| 泰宁县| 汨罗市| 平罗县| 明水县| 南阳市| 托克托县| 万源市| 普安县| 南充市| 会同县| 双牌县| 汪清县| 房产| 舞阳县| 屏南县| 丰镇市| 夹江县| 景德镇市| 嘉荫县| 祁连县| 孟津县| 崇文区| 武汉市| 修文县|