关于php是如何并行异步处理HTTP请求的这件事

在 PHP 中,由于其传统的同步阻塞模型,实现并行异步处理 HTTP 请求并不像其他语言(如 Go 或 Node.js)那样直接。#

不过,仍然可以通过一些扩展和工具来实现并行异步处理。以下是几种常见的方法:#

1. 使用 cURL 的多线程功能#

PHP 提供了 curl_multi_* 系列函数,用于实现 cURL 的多线程功能。
<?php
function curlMultiRequest(array $urls) {
    $curlHandles = [];
    foreach ($urls as $url) {
        $curlHandles[] = curl_init($url);
        curl_setopt($curlHandles[count($curlHandles) - 1], CURLOPT_RETURNTRANSFER, true);
    }

    $multiHandle = curl_multi_init();
    foreach ($curlHandles as $handle) {
        curl_multi_add_handle($multiHandle, $handle);
    }

    $active = null;
    do {
        $status = curl_multi_exec($multiHandle, $active);
        curl_multi_select($multiHandle);
    } while ($active && $status == CURLM_OK);

    $results = [];
    foreach ($curlHandles as $handle) {
        $results[] = curl_multi_getcontent($handle);
        curl_multi_remove_handle($multiHandle, $handle);
        curl_close($handle);
    }

    curl_multi_close($multiHandle);
    return $results;
}

// 示例用法
$urls = ['https://api.example.com/data1', 'https://api.example.com/data2'];
$results = curlMultiRequest($urls);

foreach ($results as $result) {
    echo $result . "\n";
}

2. 使用 Guzzle 异步客户端#

Guzzle 是一个 PHP HTTP 客户端,支持异步请求。以下是示例代码:
<?php
require 'vendor/autoload.php';

use GuzzleHttp\Client;
use GuzzleHttp\Promise;

$client = new Client();
$urls = ['https://api.example.com/data1', 'https://api.example.com/data2'];

$promises = [];
foreach ($urls as $url) {
    $promises[] = $client->getAsync($url);
}

$results = [];
foreach (GuzzleHttp\Promise\settle($promises)->wait() as $result) {
    if ($result['state'] === 'fulfilled') {
        $results[] = $result['value']->getBody()->getContents();
    }
}

foreach ($results as $result) {
    echo $result . "\n";
}

3. 使用 Swoole 扩展#

Swoole 是一个高性能的 PHP 扩展,支持协程和异步 IO。以下是示例代码:
<?php
// 确保 Swoole 扩展已安装
if (!extension_loaded('swoole')) {
    die('Swoole extension is not installed.');
}

use Swoole\Coroutine;
use Swoole\Coroutine\Http\Client;

Coroutine\run(function () {
    $urls = ['https://api.example.com/data1', 'https://api.example.com/data2'];
    $tasks = [];

    foreach ($urls as $url) {
        $tasks[] = Coroutine::create(function () use ($url) {
            $client = new Client('api.example.com', 443);
            $client->set(['timeout' => 1]);
            $client->get($url);
            return $client->body;
        });
    }

    foreach ($tasks as $task) {
        echo Coroutine::yield($task) . "\n";
    }
});

4. 使用 ReactPHP#

ReactPHP 是一个事件驱动的非阻塞 PHP 框架,支持异步 HTTP 请求。以下是示例代码:
<?php
require 'vendor/autoload.php';

use React\EventLoop\Factory;
use React\HttpClient\Client;

$loop = Factory::create();
$client = new Client($loop);

$urls = ['https://api.example.com/data1', 'https://api.example.com/data2'];
$requests = [];

foreach ($urls as $url) {
    $requests[] = $client->get($url);
}

$loop->addTimer(0, function () use ($requests, $loop) {
    foreach ($requests as $request) {
        $request->on('response', function ($response) {
            $response->on('data', function ($data) {
                echo $data;
            });
        });
    }
});

$loop->run();

5. 使用 pcntl 多进程#

pcntl 扩展允许 PHP 使用多进程编程。以下是示例代码:
<?php
$urls = ['https://api.example.com/data1', 'https://api.example.com/data2'];
$processes = [];

foreach ($urls as $url) {
    $pid = pcntl_fork();
    if ($pid == -1) {
        die('Could not fork process');
    } elseif ($pid == 0) {
        // 子进程
        $ch = curl_init($url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        $response = curl_exec($ch);
        curl_close($ch);
        echo $response . "\n";
        exit(0);
    } else {
        // 父进程
        $processes[] = $pid;
    }
}

// 父进程等待所有子进程结束
foreach ($processes as $pid) {
    pcntl_waitpid($pid, $status);
}

总结#

  • cURL 多线程:适用于简单的并发请求,使用 curl_multi_* 函数。
  • Guzzle 异步客户端:适用于需要更高级功能的 HTTP 请求,支持异步和同步请求。
  • Swoole 扩展:适用于高性能的异步和协程编程,支持异步 IO 和协程。
  • ReactPHP:适用于事件驱动的异步编程,支持异步 HTTP 请求。
  • pcntl 多进程:适用于需要多进程处理的任务,使用 pcntl_fork 创建子进程。

作者:Carver-大脸猫

出处:https://www.cnblogs.com/carver/articles/18728881

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

转载请注明原处

posted @   Carver-大脸猫  阅读(8)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示
more_horiz
keyboard_arrow_up light_mode palette
选择主题
menu