如何解决控制器中循环调用接口引发的性能缓慢及超时错误
代码优化方案
现存问题梳理
- 逻辑bug:你写的
return view逻辑放在了foreach循环体内,程序只会处理第一个id就直接返回结果,后续所有id都不会被执行,首先需要把return语句移到循环外部。 - 性能瓶颈:当前用串行方式发起HTTP请求,每一次请求都要等待上一次返回后才会发起下一次,100次请求的总耗时是所有单次请求耗时的总和,很容易触发
maximum exceed time超时错误。
具体优化方案
1. 替换串行请求为并发请求
Laravel的Http客户端原生支持并发请求,不需要逐个发送,总耗时仅等于最慢的一次请求的耗时,性能提升非常明显,优化后代码参考:
public function DeviceStatus(Request $request) { $queryinput = $request->deviceNumber; $idsArray = array_filter(explode(" ", $queryinput)); // 过滤空的无效id $deviceStatus = []; // 生成并发请求池 $requests = []; foreach ($idsArray as $id) { $requests[$id] = function () use ($id) { // 可自定义超时时间,单位为秒 return Http::timeout(10)->get('http://127.0.0.1:8000/extapi/v12/DeviceData/ByDeviceDataNumber/'.$id); }; } // 批量执行并发请求 $responses = Http::pool($requests); // 统一处理返回结果 foreach ($responses as $id => $response) { try { if ($response->successful()) { $deviceStatus[$id] = $response->json(); } else { $deviceStatus[$id] = ['status' => 'error', 'msg' => '设备数据请求失败']; } } catch (\Exception $exception) { $deviceStatus[$id] = ['status' => 'error', 'msg' => $exception->getMessage()]; } } // 循环结束后再返回视图 return view('tracedevice.ectsdevicestatus', compact('deviceStatus')); }
2. 超时配置调整
- 如果请求量级更大,可以在方法开头添加
set_time_limit(0);,临时取消当前请求的PHP运行时间上限,该配置仅对当前请求生效。
3. 可选进阶优化
- 如果被调用的
/extapi/v12/DeviceData/ByDeviceDataNumber接口支持批量查询,直接把所有id一次性传给接口,仅发起1次请求,性能比并发请求还要高。 - 如果设备状态数据更新频率不高,可以加入缓存逻辑,把查询过的设备状态缓存起来,下次查询直接读缓存,不需要重复发起HTTP请求。
内容的提问来源于stack exchange,提问作者Melx
相关产品推荐
相关产品推荐

