当前位置: 首页> 最新文章列表> 如何结合 curl_multi_exec() 和 curl_share_init() 实现并发请求优化

如何结合 curl_multi_exec() 和 curl_share_init() 实现并发请求优化

M66 2025-05-18

在现代Web开发中,处理大量HTTP请求是常见需求,例如批量抓取接口数据、并行下载资源、检查链接状态等。传统的串行请求方式(即一个请求结束后再发起下一个)效率低下。为此,PHP提供了 curl_multi_* 系列函数来实现并发请求,而 curl_share_* 系列则可以在多个cURL句柄间共享资源(如DNS缓存),进一步优化性能。本文将介绍如何结合 curl_multi_exec()curl_share_init() 来实现高效并发请求优化。

1?? 为什么要使用 curl_multi_*?

curl_multi_* 系列函数允许我们同时发送多个HTTP请求,而不是一个一个排队等候。其核心工作流程是:

  1. 初始化一个 multi handle (curl_multi_init)。

  2. 将多个 easy handle (curl_init) 加入到 multi handle。

  3. 使用 curl_multi_exec() 驱动并发请求。

  4. 使用 curl_multi_select() 等待活动句柄(避免CPU空转)。

  5. 收集结果并关闭资源。

这种方式尤其适合需要同时处理大量请求的场景,比如爬虫、接口聚合、CDN预热等。

2?? 什么是 curl_share_*?为什么要结合使用?

虽然 curl_multi_* 可以并发请求,但每个 easy handle 默认是独立的,例如每个都要单独解析DNS、维护自己的cookie等。curl_share_* 系列函数允许多个 easy handle 共享某些内部资源(如DNS缓存、SSL会话、cookie等),这样可以避免重复工作,提高性能并减少内存开销。

核心步骤包括:

  1. 使用 curl_share_init() 创建一个共享对象。

  2. 使用 curl_share_setopt() 设置共享的内容(如 CURLSHOPT_SHARE)。

  3. 使用 curl_setopt($ch, CURLOPT_SHARE, $share) 将共享对象附加到 easy handle。

  4. 请求完成后释放共享对象。

3?? 完整示例:并发请求 + 共享DNS缓存

下面提供一个实际可运行的PHP代码示例:

<?php

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

// 初始化 multi handle
$multiHandle = curl_multi_init();

// 创建共享对象
$shareHandle = curl_share_init();
curl_share_setopt($shareHandle, CURLSHOPT_SHARE, CURL_LOCK_DATA_DNS);

// 存储各个 easy handle
$curlHandles = [];

foreach ($urls as $url) {
    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_SHARE, $shareHandle);
    curl_multi_add_handle($multiHandle, $ch);
    $curlHandles[$url] = $ch;
}

// 执行并发请求
$active = null;
do {
    $mrc = curl_multi_exec($multiHandle, $active);
    if ($mrc == CURLM_CALL_MULTI_PERFORM) {
        continue;
    }
    curl_multi_select($multiHandle);
} while ($active && $mrc == CURLM_OK);

// 收集结果
$responses = [];
foreach ($curlHandles as $url => $ch) {
    $responses[$url] = curl_multi_getcontent($ch);
    curl_multi_remove_handle($multiHandle, $ch);
    curl_close($ch);
}

// 关闭 multi handle 和 share handle
curl_multi_close($multiHandle);
curl_share_close($shareHandle);

// 打印结果
foreach ($responses as $url => $content) {
    echo "Response from $url:\n";
    echo $content . "\n\n";
}

4?? 优化要点总结

? 使用 curl_multi_ 提高并发性能*:同时发起和处理多个请求,显著减少总耗时。
? 利用 curl_share_ 节省重复开销*:通过共享DNS缓存等资源,避免重复解析,提高整体效率。
? 注意资源释放:请求完成后,记得释放每个 easy handle、multi handle 和 share handle,否则可能导致内存泄漏。
? 结合 curl_multi_select():等待网络活动,避免CPU占用100%。

5?? 适用场景

  • 高并发接口聚合请求。

  • 大量页面或文件的批量抓取。

  • 网站监控、健康检查。

  • CDN或缓存预热。

结合使用 curl_multi_exec()curl_share_init(),不仅可以实现真正的并发,还能通过资源共享减少重复工作,让PHP在处理高并发网络请求时更加高效稳定。

如果你在实际应用中遇到优化瓶颈,还可以进一步结合连接池、任务调度、异常处理等手段来完善整体方案。