当前位置:首页>php>PHP 多线程:面向未来的视角

PHP 多线程:面向未来的视角

  • 2026-01-13 15:07:36
PHP 多线程:面向未来的视角

为什么写这篇文章?

在 RFC TrueAsync 1.7[1] 的背景下,有个问题随之而来:提议的 RFC 将如何与 PHP 内核未来可能的变更互动?能够对 PHP 的未来方向有基本预判,是为未来多年设计好语言的关键。这正是本文存在的原因。

TrueAsync[2] 项目不仅是为异步而修改 PHP 内核,还包含其它研究,用来回答:

  • • PHP 在多线程方向能走多远?
  • • 是否存在根本性的限制?
  • • 要让多线程成为现实,内核可能需要哪些改动?
  • • 可以实现哪些语言抽象?

我没打算让本文覆盖多线程在 PHP 中的所有细节,也没打算让每一处都技术完备或人人易懂。但希望它能对大量 PHP 开发者有用,并为后续讨论定个大致方向。

历史

几年前,我们需要在 PHP 应用里加入大体量的遥测数据,我直说“不可能”。但看到 Swoole 的架构后,想亲自验证这个结论。能否构建一个既能产生、又能处理大量数据,同时不拖慢客户端交互的 API?

我们为 PHP 做了一个优化版的 OpenTelemetry:分片写入数据,把它们聚成大块发送到中间遥测服务器。数据会被压缩,JSON 结构通过 MessagePack 序列化。

核心假设是:如果用单线程的协程,就能逐步构建遥测数据,然后按定时或体积阈值定期发到服务器。代码应该很快,因为没有跨线程交互。真是这样吗?

实验结果是:遥测让 API 吞吐下降了一半。假设失败。为什么?在_概念_层面看起来都很合理。Swoole 已经让 PHP 函数非阻塞,协程按理应该高效。是哪儿出了错?

第二版中,遥测只在单个请求期间收集,然后立即丢进一个作业进程,负责聚合、压缩并发送到服务器。这个方案好得多。但理论上不该这样!还是应该这样?进程间的数据通过 pipe 传递,一边序列化,一边反序列化。即便 pipe 在内存里,系统调用也不便宜。

之后找到原因:遥测数据太多,压缩相对 API 处理耗费了大量 CPU。也就是说,Swoole 协程对 I/O 很有效,但对 CPU 密集任务帮不上忙。

这只是众多案例之一:单线程协程不是万能的;多线程可以补充协程,组成覆盖更广问题域的工具集。

Single-threaded + offload

把 CPU 密集的工作丢到单独的进程,并不是“新发明”。它属于一种更通用的模型,在不同语言与框架中独立出现,被称为 Single-threaded + offload

想象一个人飞快地分拣信件(每小时上千封),而沉重的包裹由其他员工装车运走。如果分拣员自己去搬包裹,会怎么样?信件队伍会堆到天花板。

Single-threaded + offload 把任务分成两类:

  1. 1. I/O-bound 任务 —— 读文件、网络调用、数据库访问。大部分时间都在等待外部世界。成千上万此类操作可以通过并发异步(协程await)塞进一个线程。
  2. 2. CPU-bound 任务 —— 压缩、加密、解析、计算。这里 CPU 满负荷,仅靠并发不够,需要更多核心。

模型在物理上分隔这些任务:主线程(Event Loop)只管 I/OCPU 任务发到单独的线程或进程(Workers)。

Node.js 以单线程 Event Loop 著称,适合网络应用。但当开发者试图在请求处理里做图像处理或视频压缩时,服务器会变成南瓜。解决方案是 Worker Threads —— 用独立线程处理 CPU 重任务。

Python 的路线类似。asyncio 为 I/O 代码提供了强力工具,但内置的 GIL(全局解释器锁)阻止了单进程内的真实 CPU 并行(写文时这一问题已被解决)。因此出现了 loop.run_in_executor() 和 asyncio.to_thread()(自 Python 3.9 起),把重活丢进线程池或进程池。Event loop 依然响应灵敏,计算在并行进行。

PHP/Swoole 架构也如此:Request Workers 用协程处理 HTTP 请求,Task Workers 做重计算。通过 UnixSocket 或 pipe 通信,一个进程可处理约 10 万次每秒。

模型的优点

1. 资源利用高效

单线程的事件循环能以极低开销处理成千上万并发 I/O 操作。协程之间切换比操作系统层面的线程上下文切换更便宜。CPU-bound 任务在多核上获得真实并行——每个 worker 占用自己的核心,不互相干扰。

2. 开发更简单

事件循环里的代码不需要互斥锁、信号量等多线程“乐趣”。单线程模型意味着任意时刻只有一个任务在跑,数据竞争 不存在。Workers 虽并行运行,但如果遵守 Shared Nothing,同步问题就不出现。

多线程代码与单线程异步代码的复杂度差距巨大。现代语言与框架都更倾向单线程异步,而非传统多线程,这并不奇怪。

3. 编译器/运行时更简单

单线程模型下的异步函数对编译器和运行时来说简单得多。一个支持多线程的好语言需要专门的代码生成流程。PHP 有个严峻限制:部分代码用 C 写成。这让基于线程的高效字节码优化、内存管理、参数传递都无法实现。Go 的设计为何复杂:自研栈、复杂 GC——都是为高效的 goroutine 与 channel 服务。我们稍后还会谈到 PHP 的 GC,先别放松!

4. 手动分配负载

开发者可以有意识地把负载在请求处理代码与 worker 池代码之间分配。手动控制能把硬件潜力榨到极限。但反过来也算缺点。

模型的缺点

1. 手动分配负载

手动分配是把双刃矛。开发者可能针对场景做优化,也可能误判哪些该在 I/O 代码,哪些该在 workers。结果是 I/O 代码被重活拖垮,响应性下降,延迟上升。

模型要求 PHP 程序员有足够的能力,或者依赖框架作者的成熟方案。

2. 并非万能

Single-threaded + offload 非常适合 Web 服务器、API、微服务——主要负载是对数据库、文件系统、网络的 I/O。但若每一步都需要重计算(科研计算、渲染、机器学习),此模型可能不够高效;完整的多线程更合适。

你可能说:这些都能接受!我们准备好了!但 PHP 自身准备好多线程了吗?

PHP 准备好多线程了吗?

开发 TrueAsync 时,最难的讨论之一是“为什么 PHP 没有异步”。解释 PHP 为什么不适合多线程,可能同样棘手。不过先聊多线程:我们为什么需要它——或者更好地说:为什么我们需要它?

多线程不是为了让代码并行执行。

“并行必须用多线程”这个想法很早就扎在程序员脑中,正如“黑洞会把东西吸进去”扎在大众认知一样。

并行执行由进程就能很好完成,而且互相隔离(从 80386 架构开始)。进程可以用 IPC 交互,完成与否由信号(操作系统事件)跟踪。那么为什么需要线程?

要诚实回答,得回到过去,请当时的决策者们来说明:Edsger Dijkstra、Fernando Corbató、Barbara Liskov、Richard Rashid……我们能办场很棒的访谈。但即便他们应邀,我们也未必能得到明确答案。

不太准确的说法是:

线程是为了让并行代码无需额外工具就能共享内存。

进程也可以共享内存,但需要把内存段映射进地址空间(额外工具)。线程默认共享全部内存。字面意义上,如果变量 x 在线程 A 可用,在线程 B 就能用同样地址访问,无需任何技巧……但并非如此!多个线程不能在不加工具的情况下安全操作同一个变量。

更诚实的说法是:

线程是为了在任务间传递内存而不增加额外开销。

如果线程在传递消息时使用内存,且保证任一时刻只有一个线程能访问特定内存区域,那么这在内存和 CPU 上都是最高效的。同时线程刻意避开那些会被共享的内存区。这种模型叫 Shared Nothing

线程存在的意义,是在任务间高效传递数据。就像“黑洞不吸东西”一样真实。

PHP 的内存模型

PHP 的内存如何工作?简化的抽象模型:

  1. 1. 代码
  2. 2. 数据
  3. 3. PHP VM 状态

共享 PHP 代码在多个线程之间已经可行(PHP JIT 出现时解决了这个问题)。其余部分紧密耦合,不能轻易拆开。例如 PHP 使用全局的 object_store 存储所有对象的引用。PHP 的内存管理器为了单个 PHP VM 设计,完全没面向多线程。PHP 的 垃圾回收 无法处理不同线程的数据,还要求完全停下 PHP VM,因为它直接修改对象的 refcount

所以 PHP 是严格的单线程模型,GC 需要停世界。

在线程间移动 PHP VM

PHP 使用 线程本地存储(TLS) 按线程保存 VM 状态。这对 ZTS(Zend Thread Safety)模式下的线程隔离至关重要。

在现代 PHP 构建中,用 C11 标准的“静态”变量 __thread(MSVC 下是 __declspec(thread))获取 VM 状态指针。这种操作极快,在 x86_64 上就是从 FS 或 GS 寄存器基址加偏移读地址。

      ; offset - 编译期计算的固定偏移      ; fs - 段基址      mov rax, QWORD PTR fs:offset

因为 FS/GS 由操作系统保证每个线程唯一,从中读取总能得到正确的 VM 状态指针。

能在线程间移动 VM 状态有助于实现类似 Go 的协程或 actor。现代 VM 通过定制代码生成,用 CPU 寄存器传递 VM 上下文。PHP 做不到这一点,因为底层是 C 函数,C 无法隐式把上下文参数传给所有函数。在线程间移动 PHP VM 状态,会带来一定的性能损耗。

但如果只移动执行代码所需的一小部分 VM 状态呢?例如 PHP Fiber 切换时会复制部分全局结构指针(zend_executor_globals)。

假设把 PHP VM 概念上拆成两大块:

  1. 1. PHP VM shared:类、函数、常量、ini 指令、可执行代码。
  2. 2. PHP VM movable:需要移动的那部分 VM。
PHP VM shared vs private

部分结构可以标记为 shared,部分标记为 movable;甚至 Executor Globals 也可以拆分成 shared/movable,这样就能高效地在多线程间移动 VM 状态。扩展的全局结构不会因额外间接访问而掉性能,因为它们本就这么做。

问题在于与代码编译相关的结构,因为 PHP 具有 include/requireeval、自动加载等动态特性。正是这些特性使得高效地拆分 shared/movable VM 状态变得困难。若能解决这一点,PHP 就能以最小开销在线程间移动部分 VM 状态。

在线程间传递对象

要让 PHP 能安全在线程间传递对象,需要改什么?如何实现?

先从语言层面试试。假设我们有一个 SomeObject 实例在 $obj 里,需要把它送到另一个线程。这可能吗?

$obj = new SomeObject();$thread = new Thread(function () use ($obj{    echo $obj->someMethod();});$thread->join();

因为 SomeObject 只属于 $obj,我们可以安全地把它的地址从一个线程挪到另一个。主线程里的 $obj 会被销毁:

$obj = new SomeObject();$thread = new Thread(function () use ($obj{    echo $obj->someMethod();});// $obj is undefined here$thread->join();

这与 C++ 新增的 move 语义、或 Rust 等语言里的 move 完全等价。这种在多线程间传递内存的方式有:

  1. 1. 安全性:仅一个线程拥有对象。
  2. 2. 无复制/序列化开销。

要让行为可预测并便于静态分析,可加上专门的移动语法,例如:

$obj = new SomeObject();// consume $obj 表示移动对象$thread = new Thread(function () use (consume $obj{    echo $obj->someMethod();});// $obj is undefined here. Error should be reported here in PHP9.echo $obj;

看起来很美,对吧?

然而,仅靠 refcount = 1 的移动会有问题。来看一个分类树:

$electronics = new CategoryNode('Electronics');$categoriesTree = new Tree();$categoriesTree->addToPath('/products/electronics', $electronics);$categoriesTree->addToPath('/popular/electronics', $electronics);  // 同一个分类!

$electronics 在树里出现两次(refcount = 2)。如果把 $categoriesTree 移到另一个线程,会怎样?

要安全移动,必须保证图中所有对象没有外部引用:

$node = new CategoryNode('Electronics');$categoriesTree = new Tree();$categoriesTree->addToPath('/products/electronics', $node);$favourites = [$node];  // 外部引用!$thread = new Thread(function () use ($categoriesTree{    // $categoriesTree 已移动});// $favourites[0] 现在指向另一线程的内存// Dangling pointer!

要保证安全移动,需要:

  1. 1. 完整遍历图 —— 检查所有子对象。
  2. 2. 检查 refcount —— 图中每个对象都要查。
  3. 3. 保持身份 —— 图内的重复引用必须保持重复。

我们可以设计多个算法来做这件事,把它称为 deep copy。简单实现可能是:

// Deep copy 伪代码// 线程 A 中的源图$node = new Node('A');        // addr: 0x1000$tree->left = $node;          // addr: 0x1000$tree->right = $node;         // addr: 0x1000 (同一引用)// 拷贝到线程 B(带 MM 的伪代码)$copied_map = [];  // hash table: addr_source -> addr_targetfunction deepCopyToThread(object $obj, Thread $target_thread_mm{    $source_addr = get_object_address($obj);    if (isset($copied_map[$source_addr])) {        return $copied_map[$source_addr];  // 已复制!    }    // 在目标线程的 MM 中分配内存    $new_addr = $target_thread_mm->allocate(sizeof($obj));    $copied_map[$source_addr] = $new_addr;    // 复制对象数据    memcpy($new_addr, $source_addr, sizeof($obj));    // 递归遍历属性    foreach ($obj->properties as $prop) {        if (is_object($prop)) {            $new_prop_addr = deepCopyToThread($prop, $target_thread_mm);            // 更新新对象里的指针            update_property($new_addr, $prop, $new_prop_addr);        }    }    return $new_addr;}// 线程 B 中的结果:// $newTree->left (addr: 0x2500) === $newTree->right (addr: 0x2500)// 身份保持!

Deep copy 的时间复杂度O(N + E),其中 N 为对象数量,E 为引用数量。空间复杂度O(N) —— 哈希表 + 新对象 + 递归栈。

与序列化相比,这可能更快,因为省去转换传输格式的步骤,但收益取决于数据形状和图的大小。也可以做混合策略:refcount = 1 的数据直接移动,其余用 deep copy

结果是:

  1. 1. PHP 开发者无需关心对象如何被送到其他线程。
  2. 2. 最佳情况:内存被移动(refcount = 1)。
  3. 3. 最差情况:用 deep copy 复制内存并保持身份(refcount > 1)。

看起来不错:

  • • PHP 语法改动最小。
  • • 变更可以逐步进行。
  • • 多线程可用。

但在内核层面并非一片光明。要让对象移动成真,PHP 需要跨线程的内存管理机制,目前尚不可行。

多线程版 PHP 内存管理器

PHP 的内存管理器类似现代分配器,如 jemalloc 或 tcmalloc。区别在于,它缺少从其他线程正确释放内存的算法。

场景:

  • • 对象在线程 A 创建。
  • • 通过移动(原样)传给线程 B
  • • 在 B 不再需要,应被释放。

每个 PHP 线程都有自己的 Memory Manager (MM)。当 B 试图释放 A 分配的内存时,问题来了:B 的 MM 不认识 A 的内存,直接释放会出错。从 B 直接访问 A 的 MM 结构也不好,需要同步。现代高性能多线程分配器用延迟释放(deferred free)解决这个问题。

deferred free 的思路:

  1. 1. B 的 MM 发现一个不认识的指针。
  2. 2. 它找出该指针属于哪个 MM,向那个 MM 的队列发送“可释放”消息。
  3. 3. A 的 MM 处理队列,在自己的上下文中释放这些指针。
Cross-thread deallocation

基于现代无锁结构,这个算法吞吐高,允许不同线程并行释放内存,几乎无需锁。

多线程版的 PHP 内存管理器,会为此前不可能的其它改动打开大门。

共享对象(Shared objects)

能在不同线程间以最小操作传递内存很棒,但如果我们能直接创建为共享而设计的对象呢?

很多服务可以做成不可变对象,这样就能在不同进程间共享,节省内存、加快 PHP worker 的启动。

可惜 refcount 成了阻碍,它实际上让所有 PHP 对象都变得可变!有没有办法绕过?

代理对象

一种方式是代理对象,指向存储在所有线程都可访问的共享内存池中的真实对象。代理只保存标识或指针以及访问真实对象数据的方法。缺点:

  • • 访问数据/属性的时间变长。
  • • Reflection API 与类型计算会更复杂。

好的一面是,PHP 已有成熟的代理机制。在某些场景,代理型共享对象是好选择,例如计数器表或类似 Swoole/Table 的数据表。

带 GC_SHARE 标志的共享对象

PHP 有 GC_IMMUTABLE 标志来支持不可变元素,使用于:

  • • 驻留字符串IS_STR_INTERNED)—— 整个进程生命周期内的字符串常量。
  • • 不可变数组IS_ARRAY_IMMUTABLE)—— 例如 zend_empty_array
  • • opcache 中的常量 —— 带常量数据的已编译代码。

GC_IMMUTABLE 让引擎可以跳过这些结构的 refcount 操作:

// Zend/zend_types.h// 增加 zend_refcounted_h 引用计数的函数static zend_always_inline void zend_gc_try_addref(zend_refcounted_h *p) {    if (!(p->u.type_info & GC_IMMUTABLE)) {        ZEND_RC_MOD_CHECK(p);        ++p->refcount;    }}

类似机制可用于 SharedObjects,例如定义一个 GC_SHARE 标志。

性能分析表明,检查 GC_SHARE 会让单独的 refcount++ 多出 +34% 开销(微基准)。在真实应用里,refcount 操作只占小部分,总体影响应微乎其微:

  • • 贴近实际的操作(数组/对象):+3-9%
  • • 真实应用:+0.05-0.5%

这解决了一半问题,另一半是为此类对象设计 GC。使用原子 refcount 不是好主意,多个线程频繁访问同一对象可能拖慢性能。延迟释放算法更可能适用。

Region-based memory

面向 Web 的语言里,region-based memory 近来很流行。

思路是为特定任务或线程在独立的 region 中分配内存,当不再需要时可以整体(或几乎整体)释放,避免逐对象管理的复杂度,也简化 GC。

例如,PHP MM 可以保证在某个特定 region 中创建对象,并把该 region 绑定到某个 PHP 对象。region 的生命周期等于对象的生命周期。

当对象销毁时,整个 region 可以直接释放,无需遍历子元素。如果需要把这样的对象“移动”到另一线程,就能避免 deep copy。

PHP VM 在实现 region-based memory 时有难点,比如全局对象列表、opcode 缓存。但高效实现的可能性并非零,值得继续研究。

一个可用的 region-based memory 算法,为实现 actor(带隔离内存的特殊对象)打开了可能性。

Actor 是多线程编程里最方便、强大且安全的工具。

协程与线程的协同

对于协程而言,Thread 是一个 Awaitable 对象。协程可以等待 Thread 的结果,而不阻塞其他协程。也就是说,一个线程里可以有许多协程在等重任务的结果。处理这些协程的线程依旧能快速响应新请求,因为等待 Thread 不会阻塞事件循环。

use Async\await;use Async\Thread;$thread = new Thread(function({    // hardware-bound task here    return 42;});$result = await($thread); // 协程在此暂停,直到 Thread 完成

这种方式可以实现既有 CPU 密集任务,又有简单业务逻辑的聊天场景。

Thread + Coroutine architecture

图中是示例架构:应用包含两个线程池——并发处理请求的线程池,以及处理 CPU 密集任务的 worker 池。协程处理一个请求时,可以完全暂停,等待 worker 完成重任务后再继续。

use Async\await;use Async\ThreadPool;final readonlyclass ImageDto{    publicfunction __construct(    public int $width,    public int $height,    public string $text,{}}$pool = new ThreadPool(2);$dto = new ImageDto(    width: 200,    height: 200,    text: 'Hello TrueAsync!');$image = $pool->enqueue(function (ImageDto $dto) {    $img = imagecreatetruecolor($dto->width, $dto->height);    $white = imagecolorallocate($img, 255, 255, 255);    $black = imagecolorallocate($img, 0, 0, 0);    imagefill($img, 0, 0, $white);    imagestring($img, 5, 20, 90, $dto->text, $black);    ob_start();    imagepng($img);    imagedestroy($img);    return ob_get_clean();}, $dto);$response->setHeader('Content-Type', 'image/png');$response->write($image);$response->end();

协程代码是顺序的,看起来就像 ThreadPool::enqueue 在同一线程里调用回调一样。DTO 跨线程传递,生成的字符串也不会在内存中复制两次。

垃圾回收与 stateful 模式

升级 PHP 内存管理器只是改进多线程环境的一个方面。没有高效 GC,多线程 PHP 会因循环而出现性能问题和内存泄漏。

PHP 的 GC 使用两种算法:引用计数 作为主要的内存管理手段,并发循环收集(Bacon-Rajan,2001)用于循环引用。引用计数在每次赋值时增减,这在无同步的情况下无法安全用于多线程。每次赋值都用原子操作,开销巨大;不用同步又会产生竞争和泄漏。循环收集器虽然叫“并发”,却只在单线程内工作,使用颜色标记(PURPLE → GREY → WHITE/BLACK)找循环,这同样不是线程安全的。

好消息是,当前 GC 实现和内存管理器解耦,不依赖内存分配位置,因此在多线程环境中可以工作。

但如果 PHP 想进入 stateful 多线程时代,GC 需要适配来解决:

  1. 1. 能在单独线程 并行 工作,不影响业务代码。
  2. 2. 尽可能快地释放资源。
  3. 3. 提供额外工具来发现/记录内存泄漏、做遥测(对长时间运行的应用尤为重要!)。

循环收集器可以修改为在单独线程处理引用,提高整体响应性。作为开始,这可能已足够!

Actor

ThreadPool 和跨线程传递对象很有用,但需要开发者投入注意力与经验。还有更好的抽象,能屏蔽线程与内存的复杂性,非常适合业务逻辑:Actor

Actor 是并发并行编程模型,其中基本计算单元就是 actor

每个 actor:

  • • 拥有自己的隔离状态。
  • • 顺序处理消息。
  • • 仅通过消息与其他 actor 交互。
  • • 可以在单独的线程中运行。

可以把 actor 看作对象,因此可在多线程 PHP 中沿用熟悉的 OOP 范式。

想象一个有众多房间的聊天服务器。每个房间是一个对象。

use Async\Actor;class ChatRoom extends Actor{    private array $messages = [];    private string $name;    publicfunction __construct(string $name){        $this->name = $name;    }    publicfunction postMessage(string $user, string $text): void{        $this->messages[] = [            'user' => $user,            'text' => $text,            'time' => time()        ];    }    publicfunction getMessages(): array{        return $this->messages;    }}spawn(function() {   $room = new ChatRoom('general');   $room->postMessage('Alice', 'Hello!');  // 在另一线程执行,会挂起协程!   $messages = $room->getMessages();       // 在另一线程执行,会挂起协程!   echo json_encode($messages);});

ChatRoom 对象是特殊的:它们的数据与 PHP VM 状态被局部化,方便在线程间移动。每个方法都在独立线程中运行,但同一时刻只有一个线程能执行某个 actor 的方法。

从语义上看,基类 Actor 定义了 PHP VM 和内存管理器的工作方式,使 ChatRoom 可以安全地在独立线程中运行。类的类型不仅“存储”方法与属性的信息,还存储该类对象的内存管理与 GC 策略。类似的方法在其他语言(如 Rust、C++)中也存在。好处是无需修改语法,且自然符合现有 OOP 哲学。

示例看起来像在协程里运行的普通顺序代码。但因为 postMessage 和 getMessages 在另一个线程执行,并非直接运行。协程会向 actor 的队列发送消息,进入等待,只在 actor 在另一个线程执行完方法并返回结果时恢复。

这一切都不违背 PHP 常见的 OOP,因为 Actor 重写了 __call

class Actor{    private $threadPool;    publicfunction __call(string $name, array $arguments): mixed{        if(current_thread_id() === $this->threadPool->getThreadIdForActor($this)) {            // 如果在同一线程,直接调用            return $this->$name(...$arguments);        }        // 否则将调用加入 actor 队列        return $this->threadPool->enqueueActorMethod($this, $name, $arguments);    }}

enqueueActorMethod 把 postMessage 放入 actor 队列,订阅结果事件,并调用 Async\suspend() 挂起协程。

Actor 的代码顺序执行,消除了数据竞争,让多线程开发对程序员透明。

并行性来自每个 ChatRoom actor 都能在不同线程运行:

spawn(function() {   $room = new ChatRoom('room1');   $room->postMessage('Alice', 'Hello!');   $messages = $room->getMessages();   echo json_encode($messages);});spawn(function() {   $room = new ChatRoom('room2');   $room->postMessage('Bob', 'Hi there!');   $messages = $room->getMessages();   echo json_encode($messages);});

不同的 ChatRoom 可以在不同线程并行运行,因为每个 actor 都有自己的执行线程、独立的 PHP VM 状态和内存。

创建 100 个聊天室

use Async\Actor;$rooms = [    'general' => new ChatRoom('general'),    'random'  => new ChatRoom('random'),    'tech'    => new ChatRoom('tech'),    // ... 另外 97 个房间];// 处理请求的协程HttpServer::onRequest(function(Request $request, Response $response) use ($rooms) {   // 处理 HTTP 请求   $roomName = $request->getQueryParam('room');   $room = $rooms[$roomName] ?? null;   if (!$room) {      $response->setStatus(404);      $response->write('Room not found');      $response->end();      return;   }   // 调用看似同步,实际在另一线程运行!   $room->postMessage($request->getQueryParam('user'), $request->getQueryParam('text'));   $messages = $room->getMessages();   $response->setHeader('Content-Type',  'application/json');   $response->write(json_encode($messages));   $response->end();});

每个聊天室按顺序处理消息,同时与其他聊天室并行。

Actor 不需要互斥锁、阻塞、复杂同步或手动管理线程池。它们提供了现成的高级并行方案。

如果一个聊天室需要给另一个聊天室发消息,可以做到,因为 actor 是 SharedObject,可跨线程交互:

class Rooms extends Actor{    private array $rooms = [];    publicfunction __construct(string ...$roomNames){       foreach ($roomNames as $name) {           $this->rooms[$name] = new ChatRoom($name);       }    }    publicfunction broadcastMessage(string $fromRoom, string $user, string $text): void{        foreach ($this->rooms as $name => $room) {            if ($name !== $fromRoom) {                // 非阻塞调用                $room->postMessageAsync($user, $text);            }        }    }}spawn(function() {   $rooms = new Rooms('general', 'room1', 'room2', 'room3');   $rooms->broadcastMessage('general', 'Alice', 'Hello!');});

Actor 的内部

PHP VM 保证 actor 内的所有对象:

  • • 要么只属于该 actor,并分配在它的专有 region 中。
  • • 要么属于并被从其他 region 或线程移动过来。
  • • 要么是另一个 SharedObject 或其他 actor。

Actor 要么拥有自己的 region,要么仅与明确共享的不可变对象一起工作——否则仍会有竞争。

内存管理器保证 actor 方法中的所有内存操作都会自动绑定到与该 actor 直接关联的 region。

方法通过 MPMC 消息队列执行,由 Scheduler 负责。Scheduler 在 actor 之间分配 CPU 时间,提供并发和并行执行。

Actor model architecture

结语

这些听起来都很好,但何时能看到现实落地?你或许会问。

Single-threaded + offload 模型有望在不久后出现,因为许多组件已就绪。TrueAsync:单线程协程已到 Beta;实验版多线程内存管理器和创建线程的 API 已实现。

Actor 需要更多开发时间,它们涉及 PHP 内核的诸多部分,仍是 PHP 9 的现实目标,能为市场带来一个安全的多线程编程语言。

原文:https://github.com/true-async/multithreaded-php

引用链接

[1] RFC TrueAsync 1.7: https://wiki.php.net/rfc/true_async[2] TrueAsync: https://github.com/true-async/

最新文章

随机文章

基本 文件 流程 错误 SQL 调试
  1. 请求信息 : 2026-02-08 21:40:12 HTTP/2.0 GET : https://f.mffb.com.cn/a/460658.html
  2. 运行时间 : 0.326305s [ 吞吐率:3.06req/s ] 内存消耗:4,583.08kb 文件加载:140
  3. 缓存信息 : 0 reads,0 writes
  4. 会话信息 : SESSION_ID=ae70bcdaf18ad9475d9ba00f1e93de39
  1. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/public/index.php ( 0.79 KB )
  2. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/autoload.php ( 0.17 KB )
  3. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_real.php ( 2.49 KB )
  4. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/platform_check.php ( 0.90 KB )
  5. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/ClassLoader.php ( 14.03 KB )
  6. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_static.php ( 4.90 KB )
  7. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper.php ( 8.34 KB )
  8. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/helper.php ( 2.19 KB )
  9. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/helper.php ( 1.47 KB )
  10. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/stubs/load_stubs.php ( 0.16 KB )
  11. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Exception.php ( 1.69 KB )
  12. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Facade.php ( 2.71 KB )
  13. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/deprecation-contracts/function.php ( 0.99 KB )
  14. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap.php ( 8.26 KB )
  15. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap80.php ( 9.78 KB )
  16. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/Resources/functions/dump.php ( 1.49 KB )
  17. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-dumper/src/helper.php ( 0.18 KB )
  18. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/VarDumper.php ( 4.30 KB )
  19. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/App.php ( 15.30 KB )
  20. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Container.php ( 15.76 KB )
  21. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/container/src/ContainerInterface.php ( 1.02 KB )
  22. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/provider.php ( 0.19 KB )
  23. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Http.php ( 6.04 KB )
  24. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Str.php ( 7.29 KB )
  25. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Env.php ( 4.68 KB )
  26. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/common.php ( 0.03 KB )
  27. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/helper.php ( 18.78 KB )
  28. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Config.php ( 5.54 KB )
  29. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/app.php ( 0.95 KB )
  30. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cache.php ( 0.78 KB )
  31. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/console.php ( 0.23 KB )
  32. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cookie.php ( 0.56 KB )
  33. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/database.php ( 2.48 KB )
  34. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Env.php ( 1.67 KB )
  35. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/filesystem.php ( 0.61 KB )
  36. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/lang.php ( 0.91 KB )
  37. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/log.php ( 1.35 KB )
  38. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/middleware.php ( 0.19 KB )
  39. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/route.php ( 1.89 KB )
  40. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/session.php ( 0.57 KB )
  41. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/trace.php ( 0.34 KB )
  42. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/view.php ( 0.82 KB )
  43. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/event.php ( 0.25 KB )
  44. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Event.php ( 7.67 KB )
  45. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/service.php ( 0.13 KB )
  46. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/AppService.php ( 0.26 KB )
  47. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Service.php ( 1.64 KB )
  48. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Lang.php ( 7.35 KB )
  49. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/lang/zh-cn.php ( 13.70 KB )
  50. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/Error.php ( 3.31 KB )
  51. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/RegisterService.php ( 1.33 KB )
  52. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/services.php ( 0.14 KB )
  53. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/PaginatorService.php ( 1.52 KB )
  54. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ValidateService.php ( 0.99 KB )
  55. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ModelService.php ( 2.04 KB )
  56. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Service.php ( 0.77 KB )
  57. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Middleware.php ( 6.72 KB )
  58. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/BootService.php ( 0.77 KB )
  59. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Paginator.php ( 11.86 KB )
  60. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/Validate.php ( 63.20 KB )
  61. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Model.php ( 23.55 KB )
  62. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Attribute.php ( 21.05 KB )
  63. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/AutoWriteData.php ( 4.21 KB )
  64. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Conversion.php ( 6.44 KB )
  65. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/DbConnect.php ( 5.16 KB )
  66. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/ModelEvent.php ( 2.33 KB )
  67. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/RelationShip.php ( 28.29 KB )
  68. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Arrayable.php ( 0.09 KB )
  69. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Jsonable.php ( 0.13 KB )
  70. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/contract/Modelable.php ( 0.09 KB )
  71. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Db.php ( 2.88 KB )
  72. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/DbManager.php ( 8.52 KB )
  73. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Log.php ( 6.28 KB )
  74. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Manager.php ( 3.92 KB )
  75. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerTrait.php ( 2.69 KB )
  76. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerInterface.php ( 2.71 KB )
  77. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cache.php ( 4.92 KB )
  78. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/simple-cache/src/CacheInterface.php ( 4.71 KB )
  79. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Arr.php ( 16.63 KB )
  80. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/driver/File.php ( 7.84 KB )
  81. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/Driver.php ( 9.03 KB )
  82. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/CacheHandlerInterface.php ( 1.99 KB )
  83. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/Request.php ( 0.09 KB )
  84. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Request.php ( 55.78 KB )
  85. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/middleware.php ( 0.25 KB )
  86. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Pipeline.php ( 2.61 KB )
  87. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/TraceDebug.php ( 3.40 KB )
  88. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/middleware/SessionInit.php ( 1.94 KB )
  89. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Session.php ( 1.80 KB )
  90. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/driver/File.php ( 6.27 KB )
  91. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/SessionHandlerInterface.php ( 0.87 KB )
  92. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/Store.php ( 7.12 KB )
  93. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Route.php ( 23.73 KB )
  94. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleName.php ( 5.75 KB )
  95. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Domain.php ( 2.53 KB )
  96. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleGroup.php ( 22.43 KB )
  97. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Rule.php ( 26.95 KB )
  98. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleItem.php ( 9.78 KB )
  99. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/route/app.php ( 1.72 KB )
  100. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Route.php ( 4.70 KB )
  101. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/dispatch/Controller.php ( 4.74 KB )
  102. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Dispatch.php ( 10.44 KB )
  103. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/controller/Index.php ( 4.81 KB )
  104. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/BaseController.php ( 2.05 KB )
  105. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/facade/Db.php ( 0.93 KB )
  106. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/connector/Mysql.php ( 5.44 KB )
  107. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/PDOConnection.php ( 52.47 KB )
  108. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Connection.php ( 8.39 KB )
  109. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/ConnectionInterface.php ( 4.57 KB )
  110. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/builder/Mysql.php ( 16.58 KB )
  111. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Builder.php ( 24.06 KB )
  112. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseBuilder.php ( 27.50 KB )
  113. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Query.php ( 15.71 KB )
  114. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseQuery.php ( 45.13 KB )
  115. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TimeFieldQuery.php ( 7.43 KB )
  116. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/AggregateQuery.php ( 3.26 KB )
  117. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php ( 20.07 KB )
  118. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ParamsBind.php ( 3.66 KB )
  119. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ResultOperation.php ( 7.01 KB )
  120. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/WhereQuery.php ( 19.37 KB )
  121. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/JoinAndViewQuery.php ( 7.11 KB )
  122. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TableFieldInfo.php ( 2.63 KB )
  123. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/Transaction.php ( 2.77 KB )
  124. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/driver/File.php ( 5.96 KB )
  125. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/LogHandlerInterface.php ( 0.86 KB )
  126. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/Channel.php ( 3.89 KB )
  127. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/event/LogRecord.php ( 1.02 KB )
  128. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/Collection.php ( 16.47 KB )
  129. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/View.php ( 1.70 KB )
  130. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/View.php ( 4.39 KB )
  131. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Response.php ( 8.81 KB )
  132. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/response/View.php ( 3.29 KB )
  133. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cookie.php ( 6.06 KB )
  134. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-view/src/Think.php ( 8.38 KB )
  135. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/TemplateHandlerInterface.php ( 1.60 KB )
  136. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/Template.php ( 46.61 KB )
  137. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/driver/File.php ( 2.41 KB )
  138. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/contract/DriverInterface.php ( 0.86 KB )
  139. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/runtime/temp/067d451b9a0c665040f3f1bdd3293d68.php ( 11.98 KB )
  140. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Html.php ( 4.42 KB )
  1. CONNECT:[ UseTime:0.000464s ] mysql:host=127.0.0.1;port=3306;dbname=f_mffb;charset=utf8mb4
  2. SHOW FULL COLUMNS FROM `fenlei` [ RunTime:0.000609s ]
  3. SELECT * FROM `fenlei` WHERE `fid` = 0 [ RunTime:0.001609s ]
  4. SELECT * FROM `fenlei` WHERE `fid` = 63 [ RunTime:0.000450s ]
  5. SHOW FULL COLUMNS FROM `set` [ RunTime:0.000496s ]
  6. SELECT * FROM `set` [ RunTime:0.002391s ]
  7. SHOW FULL COLUMNS FROM `article` [ RunTime:0.000649s ]
  8. SELECT * FROM `article` WHERE `id` = 460658 LIMIT 1 [ RunTime:0.004478s ]
  9. UPDATE `article` SET `lasttime` = 1770558012 WHERE `id` = 460658 [ RunTime:0.000655s ]
  10. SELECT * FROM `fenlei` WHERE `id` = 64 LIMIT 1 [ RunTime:0.003420s ]
  11. SELECT * FROM `article` WHERE `id` < 460658 ORDER BY `id` DESC LIMIT 1 [ RunTime:0.021301s ]
  12. SELECT * FROM `article` WHERE `id` > 460658 ORDER BY `id` ASC LIMIT 1 [ RunTime:0.017221s ]
  13. SELECT * FROM `article` WHERE `id` < 460658 ORDER BY `id` DESC LIMIT 10 [ RunTime:0.092553s ]
  14. SELECT * FROM `article` WHERE `id` < 460658 ORDER BY `id` DESC LIMIT 10,10 [ RunTime:0.045050s ]
  15. SELECT * FROM `article` WHERE `id` < 460658 ORDER BY `id` DESC LIMIT 20,10 [ RunTime:0.047794s ]
0.327945s