php本身不支持原生多线程,唯一成熟可用的pthreads扩展仅兼容php 7.2–7.4且必须zts版本;其通过c层封装posix线程实现,并依赖zts隔离全局变量以避免踩踏,但php变量不共享,仅threaded对象、特定静态属性及原生c共享内存可跨线程访问。

PHP本身不支持原生多线程,所谓“多线程”全靠外部扩展实现,目前唯一成熟可用的是 pthreads(注意:仅兼容 PHP 7.2–7.4,且必须使用 ZTS 版本的 PHP 编译)。它不是在 Zend 引擎里硬塞进线程模型,而是用 C 层封装 POSIX 线程(pthread_create),再把线程生命周期、共享内存、同步原语等映射成 PHP 类接口。
为什么 pthreads 必须用 ZTS PHP?
ZTS(Zend Thread Safety)不是“让 PHP 支持线程”,而是给 Zend 内存管理器加了一层 per-thread 的存储隔离。普通 NTS PHP 的全局变量(比如 EG(scope)、CG(function_table))在多线程下会相互踩踏——一个线程改了函数表,另一个线程执行时可能直接 crash。pthreads 所有线程对象(Thread、Worker)都强制运行在独立的 ZTS 上下文中,每个线程拥有自己的 tsrm_ls(thread-safe resource manager local storage)。
- 编译时没开
--enable-maintainer-zts,加载pthreads会直接报Invalid argument或段错误 - 即使编译对了,如果 CLI 和 FPM 使用不同 ZTS 配置(比如 CLI 是 ZTS,FPM 是 NTS),
pthread对象无法跨 SAPI 传递 -
opcache在 ZTS 下默认禁用,因为 opcode 缓存本身不是线程安全的;若强行开启,需设opcache.enable_cli=1且确认所有线程只读访问
pthreads 的线程间数据共享到底怎么运作?
它不共享 PHP 变量,只共享底层 C 结构体。你写 $obj->prop = 'x',这个赋值不会自动同步到其他线程——pthreads 把对象序列化后拷贝一份到目标线程堆中,本质是深拷贝。真正能跨线程读写的只有三类东西:
-
Threaded对象:继承自该基类的属性会被特殊处理,底层用TSRMLS_DC参数传入线程局部存储,支持原子操作(lock()/unlock()) - 静态属性(
static):仅限于定义在Threaded子类里的静态属性,ZTS 下它们被映射到共享内存段 - 原生 C 共享资源:比如你自己用
shmop或sysvshm开辟的共享内存块,pthreads不干涉,但你要自己加锁
常见误用:new StdClass() 或普通数组塞进 Worker,以为能实时同步——实际只是副本,改了等于白改。
为什么 pthreads 在 PHP 8+ 彻底废弃?
不是因为“技术不行”,而是维护成本和架构冲突太大:
- PHP 8.0 彻底重构了 Zend GC 和对象模型(如
zend_object内存布局),pthreads的 C 层 hook 大量失效,补丁越打越脆弱 - 官方明确拒绝将线程安全作为核心目标,认为“进程模型 + 异步 I/O”更符合 Web 场景(见 RFC #2365)
- 替代方案已成熟:Swoole 的协程(
Swoole\Coroutine)在单线程内通过用户态调度实现并发,无锁、无 ZTS 依赖、性能更高;或者用pcntl_fork+ Unix 域套接字通信,更稳定可控
现在还硬上 pthreads,等于在 PHP 7.4 的 LTS 生命周期末期往悬崖边走——连 Ubuntu 24.04 默认源里的 PHP 都已跳过 ZTS 支持。
真正的难点不在“怎么写 Thread::start()”,而在于理解 ZTS 的边界、接受“PHP 变量不共享”这个事实,以及意识到:当你要用多线程时,往往说明架构设计已经偏离了 PHP 的舒适区。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











