curl_multi_exec() 是 curl_multi 并行请求体系中用于执行所有待处理 cURL 请求的核心函数,负责驱动多个 cURL 会话的异步执行。
函数定义
int curl_multi_exec(resource $mh, int &$still_running)
- $mh:由 curl_multi_init() 创建的多 cURL 句柄(请求管理器)
- $still_running:引用参数,返回当前仍在运行或待处理的 cURL 请求数量
返回值说明
返回 cURL 多句柄的执行状态码,常用值如下:
| 0 | CURLM_OK | 执行成功,无错误 |
| 1 | CURLM_BAD_HANDLE | 传入的 $mh 不是有效的 curl_multi 句柄 |
| 2 | CURLM_BAD_EASY_HANDLE | 某个单个 cURL 句柄无效 |
| 3 | CURLM_OUT_OF_MEMORY | 内存不足,无法执行请求 |
实际开发中,主要判断返回值是否为 CURLM_OK,其余均为异常状态。
执行机制解析
curl_multi_exec() 并非一次性完成所有请求,而是以非阻塞方式驱动请求执行:
- 调用时立即处理所有已添加到 $mh 的 cURL 请求(如建立连接、发送数据、接收响应等)
- 对于尚未完成的网络请求,通过 $still_running 返回剩余数量
- 函数立即返回,不等待全部请求结束(实现异步并行)
- 需结合循环持续调用,直到 $still_running 为 0,表示所有请求完成
典型使用示例
<?php
// 1. 初始化多cURL句柄
$mh = curl_multi_init();
// 2. 添加2个测试请求
$ch1 = curl_init('https://httpbin.org/get?test=1');
curl_setopt($ch1, CURLOPT_RETURNTRANSFER, true);
curl_multi_add_handle($mh, $ch1);
$ch2 = curl_init('https://httpbin.org/get?test=2');
curl_setopt($ch2, CURLOPT_RETURNTRANSFER, true);
curl_multi_add_handle($mh, $ch2);
// 3. 核心循环:执行直到所有请求完成
$stillRunning = 0;
do {
// 执行请求,更新$stillRunning
$execStatus = curl_multi_exec($mh, $stillRunning);
// 校验执行状态(异常处理)
if ($execStatus !== CURLM_OK) {
echo "cURL执行异常:状态码 {$execStatus}\n";
break;
}
// 关键:若还有请求未完成,等待I/O响应(减少CPU空转)
if ($stillRunning > 0) {
// curl_multi_select() 阻塞等待请求有响应,超时1秒
$selectStatus = curl_multi_select($mh, 1);
// 处理select异常(可选)
if ($selectStatus === -1) {
usleep(1000); // 休眠1毫秒,避免CPU占用100%
}
}
} while($stillRunning > 0); // 直到所有请求完成
// 4. 获取结果
echo "请求1结果:" . curl_multi_getcontent($ch1) . "\n";
echo "请求2结果:" . curl_multi_getcontent($ch2) . "\n";
// 5. 清理资源
curl_multi_remove_handle($mh, $ch1);
curl_multi_remove_handle($mh, $ch2);
curl_close($ch1);
curl_close($ch2);
curl_multi_close($mh);
?>
性能优化建议
直接循环调用 curl_multi_exec() 会导致 CPU 占用接近 100%,因为其为忙等待模式。应配合 curl_multi_select($mh, timeout) 使用,该函数会阻塞进程直至任一请求产生 I/O 响应,显著降低 CPU 消耗。建议设置合理超时时间(如 1 秒),防止无限等待。

