当前位置: 首页> 最新文章列表> 如何使用 curl_multi_close 正确结束长时间运行的请求

如何使用 curl_multi_close 正确结束长时间运行的请求

gitbox 2025-05-12

在 PHP 中,curl_multi_* 系列函数提供了一种强大的方式来同时发起多个 HTTP 请求,从而提升程序的并发性能。其中,curl_multi_close() 是一个用于清理资源的函数,它在所有并发请求完成后被调用,是释放底层资源的重要步骤。但如果使用不当,可能会导致内存泄漏或请求未完全终止的问题。

本文将通过实际代码示例,讲解如何正确使用 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);

三、常见错误及解决方案

  1. 错误:没有移除 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);
    
  2. 错误:未等待所有请求完成

    一些开发者会直接跳过 curl_multi_select() 或在 curl_multi_exec() 一次之后就直接关闭,导致部分请求未完成。使用 do-while 循环是一个可靠的方式,确保所有请求完成。

四、当请求耗时较长时该如何处理?

对于长时间运行的请求(如下载大文件或远程计算),可以采用以下方式控制:

示例(加入超时控制):

curl_setopt($ch, CURLOPT_TIMEOUT, 30); // 设置最大执行时间为30秒

五、总结

curl_multi_close() 本身并不复杂,但它必须与 curl_multi_remove_handle()curl_close() 配合使用,才能确保资源被彻底释放。在高并发请求场景中,规范地关闭 curl handle 是避免资源泄露和提升程序稳定性的关键。

使用多线程网络请求时,谨记以下顺序:

  1. 添加单个 handle 到 multi handle

  2. 执行 multi handle

  3. 获取结果

  4. 移除并关闭单个 handle

  5. 最后关闭 multi handle

通过上述方法,你可以高效地使用 curl_multi_* 系列函数,并正确地结束所有连接,提升代码的可维护性和运行效率。