介绍:为什么PHP需要并发
PHP传统上被视为同步语言,每个请求按顺序处理。然而现代Web应用需要同时执行多项任务:队列处理、API交互、图像处理、数据解析。PHP的并发和多线程技术能够解决这些问题,提升应用性能和响应能力。
本文将解析主要方法:通过pthreads实现多线程、通过pcntl_fork实现并行进程、使用ReactPHP进行异步编程,以及PHP 8.1+中的现代Fibers。每种方法都有其优势和局限性,我们将通过实际示例进行探讨。
方法1:使用pthreads扩展实现多线程
pthreads是用于PHP线程操作的扩展。它仅适用于CLI版本,且需要以--enable-maintainer-zts标志编译。线程共享内存,可高效交换数据,但需谨慎处理锁机制。
安装与配置
# 通过pecl安装
pecl install pthreads
# 在php.ini中检查
extension=pthreads.so
示例:并行处理数组
<?php
class WorkerThread extends Thread {
private $data;
private $result;
public function __construct($data) {
$this->data = $data;
}
public function run() {
// 模拟繁重操作
$this->result = array_map(function($item) {
sleep(1); // 每个元素1秒
return $item * 2;
}, $this->data);
}
public function getResult() {
return $this->result;
}
}
// 创建5个线程
$threads = [];
$dataChunks = array_chunk(range(1, 100), 20);
foreach ($dataChunks as $chunk) {
$thread = new WorkerThread($chunk);
$thread->start();
$threads[] = $thread;
}
// 收集结果
$finalResult = [];
foreach ($threads as $thread) {
$thread->join();
$finalResult = array_merge($finalResult, $thread->getResult());
}
echo "处理了 " . count($finalResult) . " 个元素,耗时约5秒而非100秒。";
重要提示: pthreads无法在Web环境(Apache/Nginx + mod_php)中运行。仅适用于CLI脚本、工作进程和守护进程。
方法2:通过pcntl_fork实现并行进程
pcntl_fork()函数创建子进程,复制当前脚本。进程间内存隔离,比线程更安全,但进程间通信(IPC)需要额外机制:消息队列、共享内存或套接字。
示例:并行下载URL
<?php
$urls = [
'https://api.example.com/data1',
'https://api.example.com/data2',
'https://api.example.com/data3',
];
$pids = [];
foreach ($urls as $url) {
$pid = pcntl_fork();
if ($pid == -1) {
die("fork错误");
} elseif ($pid == 0) {
// 子进程
$content = file_get_contents($url);
file_put_contents('/tmp/' . md5($url) . '.json', $content);
exit(0); // 务必终止子进程
} else {
$pids[] = $pid;
}
}
// 等待所有子进程结束
foreach ($pids as $pid) {
pcntl_waitpid($pid, $status);
}
echo "所有URL已并行下载完成。";
限制:
- 无法与Web服务器配合使用(仅CLI)。
- 每个进程消耗父进程内存。
- 同步访问共享资源较为复杂。
方法3:使用ReactPHP实现异步
ReactPHP是一个事件驱动编程库