当前位置: 首页> 最新文章列表> 如何在 curl_multi_close 之前判断请求是否已完成

如何在 curl_multi_close 之前判断请求是否已完成

gitbox 2025-05-12

在使用 curl_multi_* 系列函数进行并发请求时,我们通常会开启多个 curl 句柄并将它们加入到一个 curl_multi 句柄中统一管理。
为了确保在调用 curl_multi_close 释放资源之前,所有的请求都已经正确完成,我们需要合理地检测每一个请求的执行状态。本文将讲解一种标准且可靠的方法来实现这一需求。

基本流程概述

通常我们会按照以下步骤来处理多个请求:

  1. 初始化多个 curl 单独句柄。

  2. 将这些句柄添加到一个 curl_multi 句柄中。

  3. 使用 curl_multi_exec 不断地执行请求。

  4. 使用 curl_multi_select 配合 curl_multi_exec 检测是否有请求完成。

  5. 逐个移除已完成的请求句柄。

  6. 确保所有请求完成后,再调用 curl_multi_close

下面是一个完整示例,假设我们需要请求多个 URL(这里以 https://gitbox.net/example1https://gitbox.net/example2 举例):

<?php

// 初始化 cURL multi 句柄
$multiHandle = curl_multi_init();

// 存放各个 cURL 句柄的数组
$curlHandles = [];

// 要请求的 URL 列表
$urls = [
    'https://gitbox.net/example1',
    'https://gitbox.net/example2',
];

// 创建并添加每一个 cURL 句柄
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;
}

// 执行 multi 请求
$running = null;
do {
    $status = curl_multi_exec($multiHandle, $running);

    // 防止 CPU 空转
    if ($status == CURLM_OK) {
        curl_multi_select($multiHandle);
    } else {
        break;
    }

    // 检查是否有已完成的请求
    while ($info = curl_multi_info_read($multiHandle)) {
        if ($info['msg'] == CURLMSG_DONE) {
            // 获取完成的句柄
            $completedHandle = $info['handle'];

            // 获取返回内容
            $response = curl_multi_getcontent($completedHandle);

            // 可在这里处理返回的数据
            echo "请求完成,返回数据长度:" . strlen($response) . PHP_EOL;

            // 移除并关闭已完成的句柄
            curl_multi_remove_handle($multiHandle, $completedHandle);
            curl_close($completedHandle);
        }
    }
} while ($running > 0);

// 最后关闭 multi 句柄
curl_multi_close($multiHandle);

关键点解释

  • curl_multi_exec:推进并发请求的执行,返回当前仍在运行的连接数量。

  • curl_multi_select:用于阻塞等待活动连接,减少 CPU 资源浪费。

  • curl_multi_info_read:检测是否有请求完成,并可以一次性处理已完成的句柄。

  • 只有当 $running == 0,并且所有子句柄都已经被移除并关闭后,才调用 curl_multi_close

小提示

  • 如果请求很多,建议添加超时机制,以防某些请求长时间卡住。

  • curl_multi_select 有时返回 -1,在这种情况下需要使用 usleep() 进行小幅度等待,防止死循环。

简单处理 select 返回 -1 的示例:

if (curl_multi_select($multiHandle) == -1) {
    usleep(100);
}

这样可以保证脚本更加健壮。

总结

在使用 curl_multi_close 之前,关键是确认所有子请求都已经完成并正确清理,以上的模式是通用且推荐的标准做法。
多了解 curl_multi_* 系列的行为,有助于写出更高效、稳定的并发网络请求代码!