php.ini 里加:extension=swoole.so

一只肉包
一只肉包 正式会员认证极客
发布于 2026-09-23 10:40 ·8 浏览 ·0 回复

学完这篇你能得到一句话的答案:**要跑多进程用 pcntl,要做高并发常驻服务用 Swoole,想写不绑定扩展的异步代码用 Fibers——但三者根本不是一个层次的东西,选错方向会白干好几天。** 下面按"先分清定位→逐个上手→按场景选型"的顺序讲,每一步都给能直接跑的命令和最小示例。

先分清:三种并发根本不是一回事

方案本质运行位置最低要求
pcntl多进程(fork)仅 CLI编译时带 `--enable-pcntl`
Swoole常驻内存协程运行时(扩展)CLI + 自建 HTTP 服务装 PECL 扩展
Fibers语言级挂起/恢复原语任意(FPM/CLI)PHP 8.1+

pcntl 是进程级并发,Swoole 是协程 + 事件循环,Fibers 只是语法糖级别的基础设施,自己不带调度器。把 Fibers 当 Swoole 用,是最常见的踩坑。

第一步:pcntl——多进程,只在命令行生效

先确认扩展在:

php -m | grep pcntl

没有就重新编译时加 `--enable-pcntl`,宝塔下可在"软件商店→PHP→安装扩展"里勾选。

最小多进程示例:

$pids = [];
for ($i = 0; $i < 4; $i++) {
    $pid = pcntl_fork();
    if ($pid === -1) { exit('fork 失败'); }
    if ($pid === 0) {
        doJob($i);      // 子进程干活
        exit(0);        // 必须 exit,否则子进程会继续跑循环
    }
    $pids[] = $pid;
}
foreach ($pids as $pid) { pcntl_waitpid($pid, $status); }

注意:pcntl_fork 在 Apache mod_php 的 Web 请求里使用会导致进程状态错乱甚至崩溃,永远不要写在 HTTP 请求处理路径里。FPM 下虽多数环境"能调用",但父进程是 FPM worker,fork 出去的子进程不归 FPM 管理,出问题极难排查——把它当 CLI 专用工具。

适合场景:命令行批量任务、数据迁移、定时脚本分片。

第二步:Swoole——常驻内存的高并发运行时

安装(PECL 方式):

pecl install swoole

php --ri swoole | head -20

协程并发请求示例:

Swoole\Coroutine\run(function () {
    for ($i = 0; $i < 5; $i++) {
        go(function () use ($i) {
            $cli = new Swoole\Coroutine\Http\Client('example.com', 443, true);
            $cli->get('/');
            echo $i, ':', strlen($cli->body), PHP_EOL;
        });
    }
});

关键点:进入协程环境后,所有 IO 必须换成协程版 API(`Swoole\Coroutine\System::sleep` 替代 `sleep`,协程版 HTTP/MySQL/Redis 客户端替代 `file_get_contents`、PDO)。用了阻塞函数,整个进程都会被卡住,协程调度直接失效。

注意:① Swoole 与 Xdebug 常冲突,开发环境和收产环境建议分开配置;② 常驻内存意味着全局变量、静态属性、容器单例会跨请求残留,容易造成数据串号,写代码时要假设"进程不会重启";③ 扩展对 PHP 版本很敏感,装之前先查官方版本对应表,别拿 PHP 8.5 硬怼老版本 Swoole。

适合场景:自建 HTTP/WebSocket 服务、长连接、高并发 API 网关。

第三步:Fibers——PHP 8.1 原生,但只是"半成品"

$fiber = new Fiber(function () {
    $value = Fiber::suspend('first');   // 挂起,把控制权交回主流程
    echo "收到: {$value}\n";
});

echo $fiber->start(), PHP_EOL;   // 输出 first
$fiber->resume('hello');         // 输出 收到: hello

原生 Fiber 只提供 `start / resume / suspend / getReturn`,没有事件循环、没有非阻塞 IO、没有调度器。想用它做网络并发,必须搭配 Amp 或 ReactPHP 这类上层库(Amp v3 就是基于 Fiber 实现的)。

注意:`Fiber::suspend()` 只能在 Fiber 内部调用,在主流程里调会抛异常;Fiber 也不能跨进程/跨线程传递。它解决的是"把回调地狱改写成同步写法",不是"提升吞吐"。

适合场景:写不依赖扩展的异步库、在 FPM 环境里改造已有同步代码结构。

第四步:按场景选,别按热度选

  • FPM 站点里想并发几个 HTTP 请求:用 `curl_multi_*`,别上 pcntl/Swoole,改动最小。
  • CLI 批量任务、跑满多核:pcntl 多进程,简单可控。
  • 要跑常驻服务、长连接、单机万级并发:Swoole(或 Workerman、RoadRunner 这类替代品)。
  • PHP 8.1+,想把异步代码写得像同步,又不想锁死扩展:Fiber + Amp/ReactPHP。
  • 只是想把耗时操作挪出请求:消息队列 + 后台消费进程,比上面任何方案都稳。

补一句现实约束:如果你维护的是像 Clara BBS 这类无框架轻量级论坛系统(PHP 7.4–8.5 + MySQL,无需 Composer、无需命令行),它整站跑在传统 FPM 模型上,这时候引入 Swoole 属于架构级改造,性价比很低;更划算的做法是把并发需求交给队列和计划任务。并发方案要和现有运行模型匹配,而不是越先进越好。

小结

  • pcntl = 多进程,仅 CLI,Web 请求里禁用。
  • Swoole = 扩展级协程运行时,必须全程使用协程版 IO,注意常驻内存的脏状态。
  • Fibers = PHP 8.1+ 语言原语,本身不做并发,要配 Amp/ReactPHP。
  • FPM 场景优先 curl_multi 或队列,别为了并发把整个运行模型换掉。
  • 选型顺序:先看运行位置(CLI/常驻/FPM),再看是否允许装扩展,最后才看写法偏好。
本文转载自 Clara轻量论坛系统,原文地址:https://www.leleweb.cn/thread-568.html
转载请注明出处,版权归原作者所有。
他们都看过 1 人浏览过
一个达不溜

全部回复 0

还没有回复,来抢沙发~