如何使用PHP CURL实现多线程向同一URL发送大量请求
解决方案
你当前的代码是串行发送请求,每次必须等前一个请求响应完成才会发起下一个,这是耗时高的核心原因。curl_multi 完全支持同基础URL的批量请求,只需要按批次控制并发数即可,实测优化后1000次请求可压缩到10秒以内(根据网络和目标接口响应速度浮动)。
优化后的代码
<?php class API { private $url = "http://xxxxxxxxxxxxxxxx"; // 并发数,可根据目标接口承载能力调整,建议初始设10-30 private $concurrency = 20; // 单个请求超时时间,单位秒,不要设0避免无限等待 private $timeout = 10; public function __construct(){ } public function __destruct() { } public function callAPI($list, $country){ $lists = explode(",", $list); $data = []; // 分批次处理,避免并发数过高 $batches = array_chunk($lists, $this->concurrency); foreach ($batches as $batch) { $mh = curl_multi_init(); $curlHandles = []; // 批量初始化当前批次的curl句柄 foreach ($batch as $index => $id) { $url = $this->url . '/' . $country . '/' . $id; $curl = curl_init(); curl_setopt($curl, CURLOPT_URL, $url); curl_setopt($curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1); curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); curl_setopt($curl, CURLOPT_ENCODING, ''); curl_setopt($curl, CURLOPT_MAXREDIRS, 10); curl_setopt($curl, CURLOPT_TIMEOUT, $this->timeout); curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'GET'); // 开启TCP连接复用,同域名请求减少握手开销 curl_setopt($curl, CURLOPT_TCP_KEEPALIVE, 1); curl_setopt($curl, CURLOPT_FORBID_REUSE, 0); curl_multi_add_handle($mh, $curl); $curlHandles[$index] = $curl; } // 执行当前批次的并行请求 $running = null; do { $status = curl_multi_exec($mh, $running); } while ($status === CURLM_CALL_MULTI_PERFORM || $running); // 收集当前批次的响应结果 foreach ($curlHandles as $index => $ch) { $response = curl_multi_getcontent($ch); // 可在这里加错误判断,超时/状态码非200的话可以重试 $data[] = $response; curl_multi_remove_handle($mh, $ch); curl_close($ch); } curl_multi_close($mh); } return json_encode($data); } } ?>
注意事项
- 并发数不要盲目调大,过高会触发目标接口的限流策略,反而会出现大量请求失败、响应变慢的问题,建议从10开始逐步上调,找到最优值
- 如果需要更高的可靠性,可以新增重试逻辑:判断请求返回的状态码,如果是超时、5xx错误,将对应id加入下一批次重试,最多重试2-3次即可
- 若目标接口支持HTTP/2,可将
CURLOPT_HTTP_VERSION改为CURL_HTTP_VERSION_2_0,进一步降低请求开销
内容的提问来源于stack exchange,提问作者Ervis Hysi
相关产品推荐
相关产品推荐

