FrankenPHP 1.2 Worker模式仅使用多进程+协程,不依赖任何线程模型;每个worker是独立单线程进程,内部通过协程实现高并发I/O复用,规避了PHP线程安全(ZTS)的历史问题。

FrankenPHP 1.2 的 Worker 模式下,**没有线程模型,只有进程模型**。它不使用线程(thread),也不依赖 PHP 的 ext-pthreads(该扩展早已废弃且与现代 PHP 不兼容),整个运行时基于多进程 + 协程(Coroutine)架构,这是它和传统 PHP-FPM 或早期多线程尝试的本质区别。
Worker 模式只用进程,不用线程
FrankenPHP 的 Worker 模式启动后,主进程(main process)会 fork 出多个工作进程(worker processes),每个 worker 是一个独立的、单线程的 Linux 进程。它不创建任何 OS 线程,所有并发靠协程在单线程内调度完成。
- 每个 worker 进程拥有独立内存空间、文件描述符、信号处理上下文
- 进程间完全隔离:一个 worker 崩溃不会影响其他 worker
- 无共享内存、无线程同步开销(如 mutex、futex 等),也无需考虑线程安全的全局变量或静态资源
协程替代线程实现高并发
虽然每个 worker 是单线程进程,但它内部通过 Swoole 或 FrankenPHP 自带的协程运行时,支持成百上千个轻量级协程同时运行。这些协程是用户态调度的,切换成本极低(纳秒级),且自动挂起/恢复于 I/O 等待点(如 HTTP 请求、数据库查询、文件读写)。
- 协程不是线程:不映射到内核线程(no pthread_create),不参与内核调度
- 一个 CPU 核心上,一个 worker 进程可并发处理数百请求,靠的是协程让出控制权,而非抢占式线程切换
- PHP 代码仍写成同步风格(
file_get_contents、PDO::query),底层自动转为非阻塞调用
为什么 FrankenPHP 不用线程?
这不是技术做不到,而是主动规避——PHP 的 ZTS(Zend Thread Safety)模式长期维护困难,扩展兼容性差,且绝大多数 PHP 扩展(包括 OPcache、PDO、Redis、Memcached)默认非线程安全。强行启用线程会导致:
立即学习“PHP免费学习笔记(深入)”;
- 内存损坏、随机 segfault
- OPcache 失效或缓存污染
- 扩展行为不可预测(例如 curl_multi 在多线程下需特殊初始化)
- 调试和压测复杂度指数上升
FrankenPHP 选择“多进程 + 协程”组合,既保留了进程隔离的健壮性,又通过协程获得接近线程的并发密度,还彻底绕开了线程安全这个历史包袱。
对比 PHP-FPM 和传统多线程设想
PHP-FPM 同样是多进程模型(master + N workers),但它是同步阻塞的:每个请求独占一个 worker 进程,直到响应返回。FrankenPHP 的 worker 则是“一个进程 + 多协程”,能在一个 worker 内复用资源处理多个请求,单位资源吞吐更高,尤其适合 I/O 密集型场景(API 网关、微服务中台、实时数据聚合)。
- FPM worker:1 请求 = 1 进程(阻塞等待)
- FrankenPHP worker:N 请求 = 1 进程 + N 协程(非阻塞轮转)
- 两者都不用线程,但 FrankenPHP 的单进程利用率远高于 FPM



















