You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将单线程cURL改造为curl_multi_init多线程并发请求

基于curl_multi_init的并发cURL请求实现

原有改造代码存在4个核心问题:

  • 仅初始化1个cURL句柄,循环添加到multi句柄时反复复用同一资源,无法生成多个独立并发请求
  • POST参数传值错误,传入了整个分块数组而非单条请求对应的参数
  • 请求执行完成后仅读取了1个句柄的返回内容,未遍历所有并发请求获取全部结果
  • 未对每个独立cURL句柄做单独的初始化、移除、关闭操作,会造成资源泄漏

另外提供的单线程示例代码本身存在变量未定义问题:循环中$res[$key]的$key从未赋值,会产生运行警告。


正确实现代码

下面是分块并发(默认每批10个请求)的可运行版本,完全兼容原有POST请求逻辑,返回结果结构和单线程版本对齐:

<?php
// 目标请求地址
$url = 'http://localhost/test.php';
$res = [];
// 生成100条待请求的参数,对应原示例100次请求的场景
$requestList = [];
for ($i=0; $i < 100; $i++) { 
    $requestList[] = 'key='.$i;
}
// 按每批10个请求分块,避免并发数过高被目标站限流
$chunkList = array_chunk($requestList, 10, true);

// 遍历分块逐批执行并发请求
foreach ($chunkList as $chunkIndex => $chunkParams) {
    $multiHandle = curl_multi_init();
    $childHandles = [];

    // 为当前批次的每个请求初始化独立cURL句柄
    foreach ($chunkParams as $paramIndex => $postData) {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_HTTPHEADER, ["Content-type:application/x-www-form-urlencoded;charset=utf-8;"]);
        curl_setopt($ch, CURLOPT_TIMEOUT, 30);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);  
        curl_setopt($ch, CURLOPT_HEADER, 0);
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
        // 把句柄加入multi实例,同时存到数组方便后续取结果
        curl_multi_add_handle($multiHandle, $ch);
        $childHandles[$paramIndex] = $ch;
    }

    // 标准并发请求轮询逻辑
    $active = null;
    do {
        $statusCode = curl_multi_exec($multiHandle, $active);
    } while ($statusCode == CURLM_CALL_MULTI_PERFORM);

    while ($active && $statusCode == CURLM_OK) {
        if (curl_multi_select($multiHandle) != -1) {
            do {
                $statusCode = curl_multi_exec($multiHandle, $active);
            } while ($statusCode == CURLM_CALL_MULTI_PERFORM);
        }
    }

    // 逐个获取当前批次所有请求的返回结果
    foreach ($childHandles as $paramIndex => $ch) {
        // 计算全局结果索引,和原单线程返回结构保持一致
        $globalIndex = $chunkIndex * 10 + $paramIndex;
        $res[$globalIndex] = curl_multi_getcontent($ch);
        // 移除并关闭单个句柄,避免资源泄漏
        curl_multi_remove_handle($multiHandle, $ch);
        curl_close($ch);
    }

    // 关闭当前批次的multi句柄
    curl_multi_close($multiHandle);
}

var_dump($res);

使用说明

  • 每批并发数建议控制在5-20区间,具体看目标服务的承载能力,并发过高容易被限流、触发防火墙拦截,甚至造成本地端口耗尽
  • 如果需要自定义请求头、Cookie、代理、超时时间等配置,在初始化单个$ch的时候加对应的curl_setopt即可,写法和单线程cURL完全一致
  • 如果不需要获取请求返回内容,可以把CURLOPT_RETURNTRANSFER设为0,大幅降低内存占用

内容的提问来源于stack exchange,提问作者Wei Zhao

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.02 23:03:32