如何使用CURL发起大量请求且不占用全部CPU资源?
Hey there! 你遇到的CPU占满问题其实挺常见的,尤其是用循环串行发送大量CURL请求的时候。咱们一步步来分析和解决:
问题根源
你的代码功能正常但占满CPU,核心原因主要有两个:
- 同步串行请求的密集执行:300次请求挨个跑,PHP进程持续处于高负载状态,CPU几乎被循环和CURL的IO逻辑占满,没有空闲时间。
- 如果循环内重复初始化CURL句柄(虽然你的代码片段里是初始化一次,但如果实际业务中每次循环都调用
curl_init()),会额外增加资源创建/销毁的开销,进一步拉高CPU占用。
解决方案
1. 复用CURL句柄(必做基础优化)
确保只初始化一次CURL句柄,循环里仅修改POST数据并重复执行请求,这样能大幅减少资源开销。调整后的代码示例:
// 初始化CURL句柄,放在循环外部! $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, "websiteURL"); curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); curl_setopt($ch, CURLOPT_HEADER, FALSE); curl_setopt($ch, CURLOPT_POST, TRUE); curl_setopt($ch, CURLOPT_HTTPHEADER, array( "Content-Type: application/json", 'Authorization: Basic '. base64_encode("XXXXX:YYYYYY") )); // 可选:开启信号优化+设置超时,减少CPU浪费 curl_setopt($ch, CURLOPT_NOSIGNAL, 1); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5); curl_setopt($ch, CURLOPT_TIMEOUT, 10); // 循环发送300条消息 for ($i = 0; $i < 300; $i++) { // 构造本次请求的POST数据 $postData = json_encode(["message" => "你的消息内容 $i"]); curl_setopt($ch, CURLOPT_POSTFIELDS, $postData); // 执行请求 $response = curl_exec($ch); // 可选:处理请求错误 if ($response === FALSE) { error_log('Curl请求失败: ' . curl_error($ch)); } } // 最后记得关闭句柄 curl_close($ch);
2. 加入短延迟,给CPU喘息空间
如果请求太密集,哪怕复用了句柄,CPU还是会被占满,可以在每次请求后加个100-200毫秒的延迟:
// 在循环内curl_exec之后添加 usleep(100000); // 100毫秒,单位是微秒(1秒=1000000微秒)
这个小延迟能让CPU处理其他任务,避免持续高负载。
3. 用CURL多线程(批量异步请求,最优解)
对于大量请求,串行执行效率低且CPU占用高,改用CURL Multi Handle并行处理多个请求,能更合理利用CPU资源,同时提升请求速度。示例代码:
// 准备300条请求的POST数据 $postDatas = []; for ($i = 0; $i < 300; $i++) { $postDatas[] = json_encode(["message" => "你的消息内容 $i"]); } // 初始化多线程句柄 $mh = curl_multi_init(); $handles = []; // 创建所有CURL句柄并加入多线程池 foreach ($postDatas as $data) { $ch = curl_init("websiteURL"); curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); curl_setopt($ch, CURLOPT_HEADER, FALSE); curl_setopt($ch, CURLOPT_POST, TRUE); curl_setopt($ch, CURLOPT_HTTPHEADER, array( "Content-Type: application/json", 'Authorization: Basic '. base64_encode("XXXXX:YYYYYY") )); curl_setopt($ch, CURLOPT_POSTFIELDS, $data); curl_setopt($ch, CURLOPT_NOSIGNAL, 1); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5); curl_setopt($ch, CURLOPT_TIMEOUT, 10); curl_multi_add_handle($mh, $ch); $handles[] = $ch; } // 执行并行请求,关键用curl_multi_select避免空循环占CPU $running = null; do { curl_multi_exec($mh, $running); curl_multi_select($mh); // 等待请求完成,释放CPU } while ($running > 0); // 处理响应并清理资源 foreach ($handles as $ch) { $response = curl_multi_getcontent($ch); // 这里可以添加响应处理逻辑 curl_multi_remove_handle($mh, $ch); curl_close($ch); } curl_multi_close($mh);
这里的curl_multi_select($mh)是核心,它会让进程进入等待状态,直到有请求完成,不会像串行循环那样空转浪费CPU。
总结
优先尝试复用句柄+加延迟的组合,能快速降低CPU占用;如果需要更高的请求效率,直接改用CURL多线程方案,这是处理大量API请求的最优实践。
内容的提问来源于stack exchange,提问作者user9544660




