在 PHP 中,curl_multi_* 系列函数提供了一种强大的方式来同时发起多个 HTTP 请求,从而提升程序的并发性能。其中,curl_multi_close() 是一个用于清理资源的函数,它在所有并发请求完成后被调用,是释放底层资源的重要步骤。但如果使用不当,可能会导致内存泄漏或请求未完全终止的问题。
本文将通过实际代码示例,讲解如何正确使用 curl_multi_close() 来结束长时间运行的请求。
curl_multi_close() 是 curl_multi_init() 所配对的终结函数。它的作用是关闭一个多句柄资源(multi handle),并释放与之相关联的所有资源。注意,它并不会自动关闭添加到这个 multi handle 的每一个单独的 curl handle,因此我们需要手动处理。
下面是一个使用 curl_multi_* 系列函数执行多个 HTTP 请求并正确关闭资源的标准流程:
<?php
// 创建要请求的 URL 数组
$urls = [
'https://gitbox.net/api/endpoint1',
'https://gitbox.net/api/endpoint2',
'https://gitbox.net/api/endpoint3',
];
// 初始化 multi handle
$multiHandle = curl_multi_init();
$curlHandles = [];
// 为每个 URL 初始化单独的 curl handle 并添加到 multi handle 中
foreach ($urls as $i => $url) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_multi_add_handle($multiHandle, $ch);
$curlHandles[$i] = $ch;
}
// 执行所有请求
$running = null;
do {
$status = curl_multi_exec($multiHandle, $running);
if ($running) {
curl_multi_select($multiHandle); // 避免 CPU 占用过高
}
} while ($running && $status == CURLM_OK);
// 处理结果并关闭每个 curl handle
foreach ($curlHandles as $ch) {
$response = curl_multi_getcontent($ch);
$info = curl_getinfo($ch);
echo "请求状态码: " . $info['http_code'] . "\n";
echo "响应内容: " . substr($response, 0, 100) . "...\n"; // 只展示部分内容
curl_multi_remove_handle($multiHandle, $ch);
curl_close($ch);
}
// 最后关闭 multi handle
curl_multi_close($multiHandle);
错误:没有移除 handle 就关闭 multi handle
// 错误用法
curl_close($ch); // 先关闭 curl handle
curl_multi_close($mh);
正确顺序应该是:
curl_multi_remove_handle($mh, $ch);
curl_close($ch);
curl_multi_close($mh);
错误:未等待所有请求完成
一些开发者会直接跳过 curl_multi_select() 或在 curl_multi_exec() 一次之后就直接关闭,导致部分请求未完成。使用 do-while 循环是一个可靠的方式,确保所有请求完成。
对于长时间运行的请求(如下载大文件或远程计算),可以采用以下方式控制:
设置合理的 CURLOPT_TIMEOUT
使用 curl_multi_select() 减少 CPU 占用
检查并处理 curl_multi_info_read() 返回的状态
示例(加入超时控制):
curl_setopt($ch, CURLOPT_TIMEOUT, 30); // 设置最大执行时间为30秒
curl_multi_close() 本身并不复杂,但它必须与 curl_multi_remove_handle() 和 curl_close() 配合使用,才能确保资源被彻底释放。在高并发请求场景中,规范地关闭 curl handle 是避免资源泄露和提升程序稳定性的关键。
使用多线程网络请求时,谨记以下顺序:
添加单个 handle 到 multi handle
执行 multi handle
获取结果
移除并关闭单个 handle
最后关闭 multi handle
通过上述方法,你可以高效地使用 curl_multi_* 系列函数,并正确地结束所有连接,提升代码的可维护性和运行效率。