如何优化解析多JSON文件并写入指定内容的PHP脚本以提速?
嘿,我来给你分享几个能实打实提升这个脚本运行速度的优化点,都是实际项目里踩过坑后总结出来的经验:
减少磁盘IO操作,批量处理读写
磁盘IO是脚本运行的最大瓶颈之一。如果原来的逻辑是处理一个JSON就写入一次文本文件,赶紧改成先收集所有要输出的内容,最后一次性写入;或者提前打开输出文件的句柄,全程保持打开状态,避免反复打开/关闭文件的开销。另外,提前批量检查所有JSON文件是否存在,跳过不存在的文件,减少无效的文件读取尝试。不要解析整个JSON,只提取需要的字段
如果你的JSON文件体积不小,每次都用json_decode把整个文件解析成数组/对象太浪费内存和时间了。可以用这两种方式优化:- 用正则表达式直接匹配你需要的字段(适合JSON结构固定的场景),比如你要提取
temp和humidity字段,直接用preg_match从JSON字符串里抠出来就行,不用解析整个结构。 - 如果JSON结构复杂,正则搞不定,就用流式JSON解析库(比如
JsonStreamingParser),它会逐行/逐块读取JSON,只在遇到你关心的字段时进行处理,完全不用把整个JSON加载到内存里,速度和内存占用都会大幅下降。
- 用正则表达式直接匹配你需要的字段(适合JSON结构固定的场景),比如你要提取
优化内存占用,避免内存泄漏
处理大量文件时,内存堆积会拖慢脚本速度。每次处理完一个JSON文件后,记得用unset()把不再需要的变量(比如JSON字符串、解析后的临时数组)销毁掉;如果是PHP 7之前的版本,还可以偶尔调用gc_collect_cycles()手动触发垃圾回收,释放内存。缓存已处理的结果,避免重复劳动
如果这些JSON文件不是实时更新的,那就加个缓存机制:比如记录上次处理的时间,下次运行时只处理修改时间晚于上次处理时间的文件;或者直接把提取后的结果缓存到Redis、APC或者本地缓存文件里,下次读取缓存就行,不用再重新解析JSON。循环与数组操作优化
- 遍历
$wuStations数组时,用foreach代替for循环,PHP对foreach的遍历效率优化更好。 - 提前把数组里的站点ID统一格式(比如转成小写/大写),避免在循环里重复做字符串处理。
- 遍历
利用多核CPU并行处理(进阶)
如果你的服务器支持PHP的pcntl扩展,可以把站点列表分成几个批次,用多进程并行处理不同的批次,这样能充分利用多核CPU的性能,速度能提升好几倍。不过要注意处理好进程间的文件写入冲突,比如每个进程写一个临时文件,最后再合并成最终的文本文件。
举个简单的优化后代码示例(假设只提取temp和humidity字段):
// 提前收集所有存在的JSON文件路径 $validFiles = []; $outputPath = './output.txt'; foreach ($wuStations as $station) { $file = "./data/{$station}.json"; if (is_file($file) && is_readable($file)) { $validFiles[] = $file; } } // 打开输出文件句柄 $outputHandle = fopen($outputPath, 'w'); if (!$outputHandle) { die('无法打开输出文件'); } foreach ($validFiles as $file) { $jsonContent = file_get_contents($file); if (!$jsonContent) { continue; } // 用正则提取需要的字段 preg_match('/"temp":\s*(\d+\.?\d*)/', $jsonContent, $tempMatch); preg_match('/"humidity":\s*(\d+\.?\d*)/', $jsonContent, $humidityMatch); $temp = $tempMatch[1] ?? 'N/A'; $humidity = $humidityMatch[1] ?? 'N/A'; // 写入文件 fwrite($outputHandle, "{$temp},{$humidity}\n"); // 释放内存 unset($jsonContent, $tempMatch, $humidityMatch); } fclose($outputHandle);
内容的提问来源于stack exchange,提问作者korri

