爲何Swoole能夠加速php

前言

最近在研究Swoole,原來一直聽別人在說Swoole能夠加速,一直都是懵逼的。在研究了Swoole以後,我有了一些本身的理解。php

PHP-CGI 的黑歷史

對於 PHP 處理網絡請求,你們基本上也都是再用 CGI 的方式來作的。那麼,什麼是 CGI 呢。程序員

CGI

CGI,全稱 Common Gateway Interface,中文稱做「公共網關接口」。也許有不少人認爲 CGI 是一個程序,沒錯,曾經的我也是這麼認爲的。直到我從《圖解HTTP》開始細細地研究HTTP協議以後,我才知道,原來 CGI 是一種協議。任何編程語言,均可以實現 CGI,因此任何語言均可以做爲網站的後臺語言(扯遠了)。編程

PHP-CGI

上面說了,CGI 是一個協議,因此,PHP 有本身對 CGI 的實現,那就是 PHP-CGI。但是呢,隨着技術的發展,人們開始意識到,PHP-CGI 的性能不是那麼盡如人意。咱們知道,PHP 在運行的時候,是依賴配置文件 php.ini的。因此,每當 PHP-CGI 開始工做的時候,它是完徹底全的一個新進程,它須要從新加載配置文件並初始化,這就形成了很大的資源和時間的浪費。bootstrap

FastCGI

那麼,怎麼才能避免這種浪費呢,聰明的程序員們想出了另一種方法:咱們爲何不預先加載好配置,而後,每個執行的任務只須要複製當前的進程,不就能避免上面的浪費了麼。因而, FastCGI 便橫空出世。網絡

FastCGI,全稱 Fast Common Gateway Interface,中文譯做「快速公共網管接口」。沒錯,這又是個協議。固然,這個協議並非由於 PHP 纔有的。app

Apache (httpd)

幾乎全部的 Web 容器都實現了 FastCGI 的功能。首先是 httpd。對於 PHP 來講,httpd 是經過自身來實現一個 FastCGI 的模塊的。它會預先加載好 php.ini 文件中的配置。待到有請求進入須要 PHP 處理時,PHP 就不須要再對 php.ini 從新加載了。這也就是每改動過 php.ini 後都要重啓 httpd 服務的緣由。框架

Nginx 與 php-fpm

php-fpm 也是 FastCGI 的一種實現。一般咱們是將 NginxPHP 處理部分代理到 php-fpm 的端口上,交給 php-fpm 來處理。而 php-fpm 一樣是經過預先加載配置,而後給到子進程的方式的,它會對進程作一些管理。編程語言

Swoole

辣麼問題來了,php-fpm 雖然實現了 FastCGI,可是,它在處理請求的時候,依然要從新運行一個腳本,像 Laravel 同樣的框架,一開始就要加載辣麼多依賴和文件,依然是一個不小的開銷。咱們看一下 Laravelpublic/index.php 的源碼。php-fpm

require __DIR__.'/../bootstrap/autoload.php';
$app = require_once __DIR__.'/../bootstrap/app.php';
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
$response = $kernel->handle(
    $request = Illuminate\Http\Request::capture()
);
$response->send();
$kernel->terminate($request, $response);

看看前面兩條語句,這須要加載多少個依賴啊,這都是大把大把的時間和資源啊,每一次請求都須要加載一邊,真是心疼啊。性能

那麼,咱們爲何不能像以前同樣,可以不從新加載配置文件的 FastCGI ,來一個不用加載這麼多的依賴的方式呢?

固然能夠啦,這時候 Swoole 就派上用場了。既然是經過 $app->make 的方式來生成一個新的 Kernel 對象,那麼 Application 的對象 $app 天然是不會有什麼改變的了。因此,咱們能夠在收到請求以前,就把 $app 給生成好,這樣就會快了,不是麼?咱們能夠對它進行一個簡單的改造。

require __DIR__.'/../bootstrap/autoload.php';
$app = require_once __DIR__.'/../bootstrap/app.php';
$serv = new \Swoole\Server\Http('127.0.0.1', 9501);
$serv->on('request', function ($req, $res) use ($app) {
    $kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
    $response = $kernel->handle(
        $request = Illuminate\Http\Request::capture()
    );
    $res->end($response);
    $kernel->terminate($request, $response);
});
$serv->start();

好了,咱們如今就能夠經過執行這個腳原本監聽9501端口了。而後就像 Nginx 配置 php-fpm 同樣來配置它就能夠了。這樣咱們能夠看到,在收到請求以前,就已經把依賴加載乾淨了,剩下的就是處理請求了。

固然個人這個改動很簡陋,根本沒法用於生產環境的,只是提供一個例子。

後記

以上只是我本身的理解和對我本身的理解進行的總結。對於 Swoole 我還在探索當中,由於它須要的只是實在是太多了,須要一點一點積累。本文可能有不對的地方,歡迎各位大神來拍磚!

相關文章
相關標籤/搜索