PHP中的并发与多线程:实用指南

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

介绍:为什么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是一个事件驱动编程库

博客

书籍推荐