Swoole協程併發調用實踐—解決串行IO阻塞問題

前言

在傳統PHP的LNMP架構下,有些問題始終困擾着咱們,因爲PHP程序只能串行執行的特性,在IO密集型應用下,PHP程序只能在IO操做完成後才能執行後續的代碼,其中有大部分時間都在等待IO,嚴重影響執行效率,這是很是不合理。如今有這樣一個場景,一個接口須要調用10個第三方的Http接口才能拿到全部數據,假設每一個接口調用平均耗時300ms,在傳統PHP的串行模式下,須要3秒才能執行完。使用基於Swoole的協程Http客戶端能夠解決這個問題,實現Http請求的併發調用。php

實踐

下面咱們使用傳統Http客戶端Swoole協程客戶端作對比,對比方式爲,經過連續N次請求淘寶首頁,對比請求總響應時間,就可以直觀看到併發調用的優點。html

傳統Http客戶端示例

$start = microtime(true);
$n = 50;
for ($i = 0; $i < $n; $i++) {
    $http = new Http();
    $res = $http->get('https://www.taobao.com/');
    $res->getBody()->getContents();
}
$end = microtime(true);
echo bcsub($end,$start,2).PHP_EOL;

Swoole協程Http客戶端示例

go(function (){
    $start = microtime(true);
    //併發請求 n
    $result = [];
    $clients = [];
    $n = 50;
    for ($i = 0; $i < $n; $i++) {
        $cli = new \Swoole\Coroutine\Http\Client('www.taobao.com', 443,true);
        $cli->setHeaders([
            'Host' => "www.taobao.com",
            "User-Agent" => 'Chrome/49.0.2587.3',
            'Accept' => 'text/html,application/xhtml+xml,application/xml',
            'Accept-Encoding' => 'gzip',
        ]);
        $cli->set(['timeout' => 2]);
        $cli->setDefer();
        $cli->get('/');
        $clients[] = $cli;
    }

    for ($i = 0; $i < $n; $i++) {
        if (!$clients[$i]->recv()) {
            continue;
        }

        $result[] = $clients[$i]->body;
    }

    $end = microtime(true);
    echo bcsub($end,$start,2).PHP_EOL;
});

數據分析

調用次數 響應時間(協程) 響應時間(傳統)
10 1.09s 3.64s
20 2.33s 7.27s
30 2.89s 14.91s
50 3.96s 17.57s
100 7.33s 37.23s

經過上面的數據能夠看到,協程模式速度是傳統模式的好幾倍,並且隨着調用次數增多,協程模式的速度優點愈來愈明顯,這就IO密集型場景下,異步模式帶來的巨大性能提高。架構

串行調用、併發調用 圖解

圖片描述

總結

若是你們和我同樣,在IO密集型場景下,程序的速度到了瓶頸,不管怎麼優化,速度都沒有質的提高,那麼能夠嘗試使用Swoole的協程模式,可能會帶來意想不到的效果。在大多數Web場景下,並非咱們的程序執行慢,而是大多數時間都在等待IO結束,不管怎麼優化代碼提高都不明顯,不如換個思路,使用協程異步來解決IO等待問題,帶來的提高是巨大的。但願本篇文章對你有幫助!併發

相關文章
相關標籤/搜索