使用big-json流式写入文件为何速度慢?如何优化性能?
一、big-json耗时更高的原因
流式处理的额外开销
big-json核心是流式序列化+写入,会把数据拆分成小块逐步处理,过程中涉及大量事件循环调度、流背压处理、分块序列化逻辑。但你已经把1000万条数据全量加载到内存,这些流式处理的额外操作完全冗余——原生JSON.stringify是一次性在内存完成全量序列化,再通过fs.writeFileSync一次性写入,没有这类额外开销。原生API的底层优化
V8引擎对JSON.stringify做了极致底层优化,包括汇编级批量处理、内存复用等,性能远高于JavaScript实现的第三方序列化逻辑。big-json作为JS库,无法享受这些底层优化,速度自然跟不上。超大数据场景的冗余逻辑
big-json设计初衷是处理无法全量加载到内存的超大JSON,内置了大量分块、内存管控逻辑。但你的数据已经全在内存中,这些逻辑不仅没用,还会增加额外计算成本。
二、性能提升方案
1. 内存足够时,直接用原生组合(最快方案)
如果机器内存能容纳全量数据(1000万条这类结构的数据约占500MB,大部分现代机器可轻松处理),直接用JSON.stringify+fs.writeFileSync是性能最高的选择:
import fs from 'fs'; const myData = []; for (let i = 0; i < 10000000; ++i) { myData.push({'id': i, 'name': 'SomeName'}); } const fetchAt = new Date(); console.log("Starting saving ..."); fs.writeFileSync('./myfile.json', JSON.stringify(myData)); const writeAt = new Date(); console.log(`Data written in ${(writeAt - fetchAt) / 1000} seconds.`);
2. 内存紧张时,手动分块原生序列化
若担心全量序列化内存占用过高,可手动把数据分成小批次,用JSON.stringify处理每一批,再拼接成合法JSON数组写入流——既控制内存,又比big-json快:
import fs from 'fs'; const myData = []; for (let i = 0; i < 10000000; ++i) { myData.push({'id': i, 'name': 'SomeName'}); } const batchSize = 100000; // 每批次处理10万条 const stream = fs.createWriteStream('./myfile.json'); stream.write('['); // 写入数组开头 const fetchAt = new Date(); console.log("Starting saving ..."); for (let i = 0; i < myData.length; i += batchSize) { const batch = myData.slice(i, i + batchSize); const chunk = JSON.stringify(batch); // 去掉批次JSON的前后[],并处理逗号分隔 if (i > 0) stream.write(','); stream.write(chunk.slice(1, chunk.length - 1)); } stream.write(']'); // 写入数组结尾 stream.end(() => { const writeAt = new Date(); console.log(`Data written in ${(writeAt - fetchAt) / 1000} seconds.`); });
3. 用schema优化的序列化库
如果数据结构固定(比如每条都是{id: number, name: string}),可以用fast-json-stringify这类基于预定义schema的序列化库,它生成的序列化函数比原生JSON.stringify更快:
import fastJson from 'fast-json-stringify'; import fs from 'fs'; // 预定义数据schema const stringify = fastJson({ type: 'array', items: { type: 'object', properties: { id: { type: 'integer' }, name: { type: 'string' } } } }); const myData = []; for (let i = 0; i < 10000000; ++i) { myData.push({'id': i, 'name': 'SomeName'}); } const fetchAt = new Date(); console.log("Starting saving ..."); fs.writeFileSync('./myfile.json', stringify(myData)); const writeAt = new Date(); console.log(`Data written in ${(writeAt - fetchAt) / 1000} seconds.`);
内容的提问来源于stack exchange,提问作者Clyde Barrow

