如何比file_get_contents更快读取URL?批量运行PHP页面优化求助
解决100个PHP页面串行执行过慢的问题
你的问题核心在于串行请求每个页面——每个file_get_contents都要等前一个请求完成才能开始,总耗时是所有请求时间的总和,外部服务器的网络延迟、资源限制都会放大这个问题。下面是几个靠谱的优化方案:
1. 使用Curl Multi实现并行请求
这是最直接的优化,一次性发起多个HTTP请求,不用等单个请求完成再继续。相比串行,总耗时会接近最慢的那个请求的时间,而不是所有请求时间相加。
示例代码:
<?php // 生成要请求的URL列表 $urls = []; for ($i = 1; $i <= 100; $i++) { $urls[] = "http://website.com&page{$i}"; } // 初始化curl_multi句柄 $mh = curl_multi_init(); $handles = []; // 为每个URL创建curl实例并加入批量请求 foreach ($urls as $url) { $ch = curl_init($url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); curl_setopt($ch, CURLOPT_TIMEOUT, 30); // 设置单个请求超时时间 $handles[] = $ch; curl_multi_add_handle($mh, $ch); } // 执行并行请求 $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); ?>
提示:可以根据服务器承受能力分批次执行(比如每次并行10个,分10批),避免一次性发起100个请求导致服务器过载。
2. 引入队列系统实现异步处理
如果你的任务不需要立即拿到所有结果,用队列拆分任务是更稳妥的方式。比如用Redis做队列,配合多个消费者进程并行处理:
- 生产者脚本:把100个页面URL加入队列
<?php $redis = new Redis(); $redis->connect('127.0.0.1', 6379); for ($i = 1; $i <= 100; $i++) { $url = "http://website.com&page{$i}"; $redis->lPush('page_process_queue', $url); } ?>
- 消费者脚本:从队列取URL并处理,可同时启动多个消费者进程(比如5个)
<?php $redis = new Redis(); $redis->connect('127.0.0.1', 6379); while (true) { $url = $redis->rPop('page_process_queue'); if (!$url) { break; // 队列空了就退出 } // 执行页面请求 file_get_contents($url); // 可选:添加日志记录执行状态 } ?>
可以用supervisord或定时cron管理消费者进程,既能灵活控制并发数,也能在请求失败时重新入队重试。
3. 用Shell脚本配合Curl/Wget并行执行
如果不想写复杂的PHP代码,Shell脚本是更轻量的选择,用xargs控制并发数:
# 同时启动10个进程,处理1-100号页面 seq 1 100 | xargs -P 10 -I {} curl "http://website.com&page{}"
-P 10表示并发数,可根据服务器性能调整。如果需要记录执行结果,可将输出重定向到日志文件:
seq 1 100 | xargs -P 10 -I {} curl "http://website.com&page{}" >> page_process.log 2>&1
4. 优化单个页面的执行效率
最后别忘了从根源优化——如果每个PHP页面本身执行就很慢,哪怕并行也快不了多少。可以检查:
- 数据库查询是否有优化空间(比如添加索引、合并重复查询)
- 是否有重复计算/IO操作,用Redis、Memcached等缓存结果
- 关闭不必要的调试输出,减少页面加载耗时
内容的提问来源于stack exchange,提问作者 phong
相关产品推荐
相关产品推荐

