當前位置: 首頁> 最新文章列表> 如何用curl_multi_* 系列函數搭配curl_share_init() 實現高性能並發請求

如何用curl_multi_* 系列函數搭配curl_share_init() 實現高性能並發請求

M66 2025-06-02

在 PHP 中,我们经常需要与外部 API、网站或服务进行网络请求。常规的 curl_exec() 单个请求虽然简单,但在高并发场景下,它的性能瓶颈非常明显:每个请求都是顺序执行的,等待上一个请求完成才能开始下一个,导致整体耗时线性增长。

为了提高网络请求效率,PHP 提供了两个非常强大的工具:curl_share_init()curl_multi_* 系列函数。本文将深入介绍如何使用它们实现高性能并发请求。

1?? curl_share_init() 的作用

curl_share_init() 用于在多个 cURL 句柄之间共享数据,比如 DNS 缓存、Cookie、SSL 会话等。

举个例子:如果你需要同时请求多个相同域名的地址,启用共享 DNS 缓存可以显著减少 DNS 查询时间。

$sh = curl_share_init();
curl_share_setopt($sh, CURLSHOPT_SHARE, CURL_LOCK_DATA_DNS);

这段代码初始化了一个共享句柄,并设置为共享 DNS 数据。接下来我们会将这个共享句柄绑定到每个 curl 请求上。

2?? curl_multi_* 系列函数的作用

curl_multi_* 系列函数允许我们同时发起多个 HTTP 请求,而不是像 curl_exec() 那样一个接一个地发。

主要函数包括:

3?? 实战示例:并发请求多个 URL

下面是一个完整示例,展示如何使用 curl_share_init()curl_multi_* 系列函数并发请求多个地址。

<?php

// 要請求的 URL 列表
$urls = [
    'https://m66.net/api/endpoint1',
    'https://m66.net/api/endpoint2',
    'https://m66.net/api/endpoint3'
];

// 初始化共享句柄
$sh = curl_share_init();
curl_share_setopt($sh, CURLSHOPT_SHARE, CURL_LOCK_DATA_DNS);

// 初始化 multi 句柄
$mh = curl_multi_init();
$curl_handles = [];

// 為每個 URL 創建單獨的 curl 句柄
foreach ($urls as $i => $url) {
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_SHARE, $sh); // 綁定共享句柄
    curl_multi_add_handle($mh, $ch);
    $curl_handles[$i] = $ch;
}

// 執行所有請求
$running = null;
do {
    $status = curl_multi_exec($mh, $running);
    if ($status > 0) {
        echo "cURL error: " . curl_multi_strerror($status) . "\n";
    }
    // 等待活動連接
    curl_multi_select($mh);
} while ($running > 0);

// 獲取結果
$responses = [];
foreach ($curl_handles as $i => $ch) {
    $responses[$i] = curl_multi_getcontent($ch);
    curl_multi_remove_handle($mh, $ch);
    curl_close($ch);
}

// 關閉 multi 和 share 句柄
curl_multi_close($mh);
curl_share_close($sh);

// 輸出結果
foreach ($responses as $i => $response) {
    echo "Response from URL $i:\n$response\n\n";
}
?>

4?? 性能提升分析

使用 curl_multi_*,所有请求会尽量并发执行,整体耗时接近最长单个请求的耗时,而不是总和。

使用 curl_share_init(),则能减少重复的 DNS 查询、SSL 握手等开销,进一步优化性能。

在高并发、需要频繁请求相同域名 API 的场景(例如同时抓取多个接口、批量爬取网页、同步多个微服务数据等),这种组合能显著提升效率。

5?? 注意事项

  • DNS 共享不是总能显著提速:主要在相同域名、多请求下见效。

  • 合理设置超时:并发中某个请求卡住可能影响整体。

  • 控制并发数量:请求太多可能导致服务器或本地资源耗尽,可以用信号量或批次分发。

  • 错误处理:示例中未详细处理单个请求失败,实际应用需要补充。