 1.文档阅读
PHP-FPM vs Swoole | PHP 技术论坛
为什么Swoole可以加速php
React PHP vs Swoole PHP · Issue #389 · php-pm/php-pm · GitHub -- 国外开发者对swoole的测试
https://github.com/swoole/swoole-src/issues/1687
2.整理输出 基于「PHP-FPM vs Swoole | PHP 技术论坛」文章进行修改和补充
前几天看见有几篇讲 swoole 的文章,今天我也来凑个热闹。
水平有限,细节理解可能不到位,欢迎大家帮我补充、纠正。
PHP-FPM
早期版本的 PHP 并没有内置的 WEB 服务器,而是提供了 SAPI(Server API)给第三方做对接。
现在非常流行的 php-fpm 就是通过 FastCGI 协议来处理 PHP 与第三方 WEB 服务器之间的通信。
比如 Nginx + php-fpm 的组合,这种方式运行的 fpm 是 Master/Worker 模式,启动一个 Master 进程监听来自 Nginx 的请求,再 fork 多个 Worker 进程处理请求。每个 Worker 进程只能处理一个请求,
单一进程的生命周期大体如下:
- 初始化模块。
- 初始化请求。此处请求是请求 PHP 执行代码的意思,并非 HTTP 的请求。
- 执行 PHP 脚本。
- 结束请求。
- 关闭模块。
对细节感兴趣的可以点这里看图

多进程模型是依赖进程数来解决并发问题,一个进程只能处理一个连接,当启动大量进程,进程调度消耗可能占 CPU 的百分之几十甚至 100%,比如 C10K 问题,多进程模型就力不从心了。
Swoole
Swoole 采用的也是 Master/Worker 模式,不同的是 Master 进程有多个 Reactor 线程,Master 只是一个事件发生器,负责监听 Socket 句柄的事件变化。
Worker 以多进程的方式运行,接收来自 Reactor 线程的请求,并执行回调函数(PHP 编写的)。
启动 Master 进程的流程大致是:
- 初始化模块。
- 初始化请求。因为 swoole 需要通过 cli 的方式运行,所以初始化请求时,不会初始化 PHP 的全局变量,如 $_SERVER, $_POST, $_GET 等。
- 执行 PHP 脚本。包括词法、语法分析,变量、函数、类的初始化等,Master 进入监听状态,并不会结束进程。
Swoole 加速的原理
由 Reactor(epoll 的 IO 复用方式)负责监听 Socket 句柄的事件变化,解决高并发问题。 通过内存常驻的方式节省 PHP 代码初始化的时间,在使用笨重的框架时,用 swoole 加速效果是非常明显的。
对比不同
PHP-FPM
- Master 主进程 / Worker 多进程模式。
- 启动 Master,通过 FastCGI 协议监听来自 Nginx 传输的请求。
- 每个 Worker 进程只对应一个连接,用于执行完整的 PHP 代码。
- PHP 代码执行完毕,占用的内存会全部销毁,下一次请求需要重新再进行初始化等各种繁琐的操作。
- 只用于 HTTP Server。
Swoole
- Master 主进程(由多个 Reactor 线程组成)/ Worker 多进程(或多线程)模式
- 启动 Master,初始化 PHP 代码,由 Reactor 监听 Socket 句柄的事件变化。
- Reactor 主线程负责子多线程的均衡问题,Manager 进程管理 Worker 多进程,包括 TaskWorker 的进程。
- 每个 Worker 接受来自 Reactor 的请求,只需要执行回调函数部分的 PHP 代码。
- 只在 Master 启动时执行一遍 PHP 初始化代码,Master 进入监听状态,并不会结束进程。
- 不仅可以用于 HTTP Server,还可以建立 TCP 连接、WebSocket 连接。
以上主要针对核心运行机制作对比,列举的不同,暂时就想到这几点了,如果有漏掉的重点,欢迎大家帮我补充啦~
评论也是引人思考:

整理如下:
TBD
考虑一个问题: 为什么都是常驻内存的方式,PHP-FPM与Swoole的性能差距有些大呢? 下面的解答并没有切中要害, 实际上web应用中在处理http请求的表现孰强孰弱未可知~ 建议, 先去把swoole和php-fpm的官方文档都阅读一下, 应该会有一个初步大的答案.
高性能 ≠ 多线程
高性能 ≠ 异步
高性能 ≠ 常驻
高性能 ≠ 复用资源 如果您真的很喜欢 Swoole 建议你先阅读官方文档,理解「概述」所说的事情!
php-fpm vs swoole 本身定位并不是相同的,这两个比较没有说服力。其次,swoole 跟多的是解决一些 php 覆盖不到的问题,例如协程、异步,还有就是协议通信这一块,其次就是 php-fpm 薄弱的地方,例如 Windows 环境,虽然 swoole 也正在改善 Windows 支持,但是依旧不好。与其说 swoole 来和 php-fpm 对比,不如说 swoole 是在拓展 php 的更多可行性。
解答:
Nginx 与 php-fpm
php-fpm 是 FastCGI 的一种实现。
通常我们是将 Nginx 的 PHP 处理部分代理到 php-fpm 的端口上,交给 php-fpm 来处理。
而 php-fpm 同样是通过预先加载配置,然后给到子进程的方式的,它会对进程做一些管理。
Swoole
那么问题来了, php-fpm 虽然实现了 FastCGI ,但是,它在处理请求的时候,依然要重新运行一个脚本,像 Laravel 一样的框架,一开始就要加载很多的依赖和文件,依然是一个不小的开销。
我们看一下 Laravel 的 public/index.php 的源码。
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 给生成好,这样就会快了,不是么?
「实际上,还要处理一些超全局变量的问题,需要在每次接收新请求时,将这些超全局变量还原等,
具体可以参见:swoole 适配一些php-fpm web开发框架的适配,如thinkphp,laravel,yii
推荐看下:swoole (P1. 1-1 课程导学)_哔哩哔哩_bilibili ,这个教程有点老了,是关于swoole 2.x版本,但是依然有学习借鉴的价值」
我们可以对它进行一个简单的改造。「这里的改造,并不完全,实际上还会很多坑,比如请求的参数也要处理/还原,否则一直是第一次请求的信息/数据,等等, 而且加载文件这块,可能放在workstart事件更合适」
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 一样来配置它就可以了。「不再需要Nginx和PHP-FPM,因为swoole已经提供了http服务器,而且支持php-cgi程序」
这样我们可以看到,在收到请求之前,就已经把依赖加载干净了,剩下的就是处理请求了。
当然我的这个改动很简陋,根本无法用于生产环境的,只是提供一个例子。
后续补充 ... |