PHP 中的并发与多线程简介
PHP 传统上被认为是一种同步、单线程的语言。然而,现代 Web 应用程序需要同时处理多项任务:文件上传、API 调用、队列处理。PHP 中的并发与多线程能够解决这些问题,加快脚本执行速度,提升应用程序的响应能力。
在本文中,我们将剖析关键概念:从并发的基本原理到 pthreads 和 parallel 扩展的实际应用。您将学习如何组织任务的并行执行、避免数据竞争以及提升 PHP 代码的性能。
并发与多线程的核心概念
同步 vs 异步
在同步模型中,PHP 严格按顺序执行代码。如果一个脚本发起 HTTP 请求,执行过程会暂停直到收到响应。异步则允许启动任务而不必等待其完成。
同步代码示例:
<?php$result1 = file_get_contents('https://api.example.com/data1');$result2 = file_get_contents('https://api.example.com/data2');// 两个请求按顺序执行?>线程与进程
- 进程 — 拥有独立地址空间的程序副本。
- 线程 — 进程内部的轻量级执行单元,共享内存。
在 PHP 中,多线程通过线程(threads)实现。由于标准 PHP 构建不支持线程,需要使用专门的扩展。
数据竞争与同步
当多个线程操作共享数据时,可能会发生竞态条件(race condition)。为了防止这种情况,需要使用互斥锁(mutex)、锁机制和原子操作。
PHP 多线程工具
pthreads 扩展
pthreads 是最早用于处理线程的扩展之一。它提供了 Thread、Worker 和 Pool 类。重要提示:该扩展仅在 CLI 模式下工作,并且需要 ZTS(Zend 线程安全)版本的 PHP 构建。
简单线程示例:
<?phpclass MyThread extends Thread { public function run() { echo "线程已启动"; }}$thread = new MyThread();$thread->start();$thread->join();?>parallel 扩展
parallel 是一个更现代的扩展,自 PHP 7.4 起可用。它更便捷、更安全。通过通道(channels)在线程之间传输数据。
使用 parallel 的示例:
<?php$runtime = new \\parallel\\Runtime();$future = $runtime->run(function(){ return "来自并行线程的问候!";});echo $future->value(); // 获取结果?>通过 ReactPHP 和 Amp 实现异步
如果您不需要真正的多线程,但需要并发,请使用异步 I/O 库:
- ReactPHP — 基于事件循环的事件驱动库。
- Amp — 为 PHP 提供 async/await 支持,类似于 JavaScript。
实践示例与最佳实践
示例:并行处理 URL
假设需要检查 10 个网站的可访问性。同步方式会花费大量时间。使用 parallel 来加速:
<?php$urls = [ 'https://google.com', 'https://yandex.ru', 'https://github.com'];
$runtimes = [];$futures = [];
foreach ($urls as $url) { $runtime = new \\parallel\\Runtime(); $runtimes[] = $runtime; $futures[] = $runtime->run(function($url) { $ch = curl_init($url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_TIMEOUT, 5);