PHP使用curl_multi_init加载3万URL返回空值,如何控制并发数为10?
问题根源与解决方案
你遇到的问题核心是:一次性把3万个请求句柄全加到curl_multi里了——哪怕CURLMOPT_MAXCONNECTS默认是10,curl会尝试在后台排队处理,但系统的文件句柄、网络带宽等资源根本扛不住这么多并发请求排队,最终导致大量请求超时失败。
要实现严格的「每次仅处理10个请求」,需要分批加载+动态补充的逻辑:先启动第一批10个请求,每完成一个就立刻补上一个新的,始终保持同时活跃的请求数不超过10。
修改后的完整代码
$mh = curl_multi_init(); // 设置总并发连接数上限为10(核心控制项) curl_multi_setopt($mh, CURLMOPT_MAX_TOTAL_CONNECTIONS, 10); // 每个主机的最大连接数(可选,按需调整) curl_multi_setopt($mh, CURLMOPT_MAXCONNECTS, 10); $requests = []; $responses = []; $urlCount = count($urls); $currentIndex = 0; $active = 0; // 加载第一批10个请求 for (; $currentIndex < min(10, $urlCount); $currentIndex++) { $url = $urls[$currentIndex]; $ch = curl_init($url); // 复用你的curl配置 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_TIMEOUT, 8); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_HEADER, false); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36'); curl_multi_add_handle($mh, $ch); $requests[(int)$ch] = $currentIndex; // 用句柄映射URL索引,保证响应顺序 } do { // 执行多请求并获取活跃连接数 $execStatus = curl_multi_exec($mh, $active); // 等待连接状态变化,避免空循环占用CPU if ($execStatus == CURLM_OK) { curl_multi_select($mh); } // 读取所有已完成的请求信息 while ($info = curl_multi_info_read($mh)) { $ch = $info['handle']; $urlIndex = $requests[(int)$ch]; // 根据请求结果处理响应 if ($info['result'] == CURLE_OK) { $responses[$urlIndex] = curl_multi_getcontent($ch); } else { $responses[$urlIndex] = false; // 可选:打印错误详情用于排查 // echo "URL {$urls[$urlIndex]} 失败: " . curl_error($ch) . "\n"; } // 清理已完成的请求句柄 curl_multi_remove_handle($mh, $ch); curl_close($ch); unset($requests[(int)$ch]); // 加载下一个请求,直到所有URL处理完毕 if ($currentIndex < $urlCount) { $url = $urls[$currentIndex]; $newCh = curl_init($url); // 复用相同配置 curl_setopt($newCh, CURLOPT_RETURNTRANSFER, true); curl_setopt($newCh, CURLOPT_TIMEOUT, 8); curl_setopt($newCh, CURLOPT_CONNECTTIMEOUT, 5); curl_setopt($newCh, CURLOPT_SSL_VERIFYHOST, false); curl_setopt($newCh, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($newCh, CURLOPT_HEADER, false); curl_setopt($newCh, CURLOPT_FOLLOWLOCATION, true); curl_setopt($newCh, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36'); curl_multi_add_handle($mh, $newCh); $requests[(int)$newCh] = $currentIndex; $currentIndex++; } } } while ($active > 0 || $currentIndex < $urlCount); // 关闭多请求句柄 curl_multi_close($mh); // 响应数组与原URL数组顺序一致 // print_r($responses);
关键逻辑说明
CURLMOPT_MAX_TOTAL_CONNECTIONS:直接控制curl_multi同时允许的总连接数,设置为10就确保最多同时跑10个请求。- 动态补充机制:每次有请求完成就立刻加载下一个未处理的URL,始终保持并发量稳定,避免一次性占用过多系统资源。
- 响应顺序保证:通过请求句柄映射原URL的索引,最终
$responses数组会和输入的$urls数组顺序完全一致。 - 错误排查:通过
curl_multi_info_read获取请求结果状态,能快速定位失败的URL及原因。
内容的提问来源于stack exchange,提问作者Mr J
相关产品推荐
相关产品推荐

