ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

大文件JSON逐行流式解析:如何用REDox异步处理NDJSON,让内存占用骤降

大文件JSON逐行流式解析:如何用REDox异步处理NDJSON,让内存占用骤降 大文件JSON逐行流式解析如何用REDox异步处理NDJSON让内存占用骤降【免费下载链接】REDoxHigh-performance, token-based structured data engine for .NET. A core component of REX, the technology behind CAPCOMs next-generation game engine.项目地址: https://gitcode.com/gh_mirrors/redox/REDox你是否遇到过这样的场景一个几十 GB 的 JSON 日志文件用JsonDocument.Parse或Deserialize一次性读入程序直接内存溢出REDox是 CAPCOM 为 REX 次世代游戏引擎打造的 .NET 高性能结构化数据引擎它的 JsonSequence API 专为「大文件 JSON 流式解析」而生——可以逐行异步读取 NDJSON每行一个 JSON 对象也可以流式解析巨型顶层数组全程不加载整个文件内存占用骤降。痛点一次性加载大 JSON 为什么会爆内存传统做法是把整个文件读进内存再解析文件全部加载到byte[]或字符串解析器再建一套对象树峰值内存往往是文件大小的数倍对于服务器日志、埋点数据、游戏遥测这类 NDJSON 大文件逐行流式解析才是正确姿势读一行、处理一行、丢弃一行内存占用与文件大小脱钩。REDox 的 JsonSequence为 NDJSON 流式解析而设计JsonSequence.cs 提供了两个核心入口都返回IAsyncEnumerable配合await foreach使用JsonSequence.DeserializeAsyncT(stream, ...)—— 把流中的每个 JSON 值反序列化为 .NET 对象TJsonSequence.ParseAsync(stream, ...)—— 返回轻量级DElement直接操作 token DOM无需中间对象它支持两种输入形态见 README.md 的 Async streaming of NDJSON / JSON sequences 一节输入形态如何开启适用场景NDJSON / JSON Lines每行一个 JSON设置UseNewlineDelimitedFormat true日志、事件流、逐行追加的大文件顶层大数组[ {...}, {...} ]默认即可一次性导出的大数组文件 换句话说无论你的大文件是「一行一个对象」还是「一个巨大的数组」REDox 都能边读边产出元素。三步上手大文件 NDJSON 逐行异步解析第一步安装核心包dotnet add package CAPCOM.REDox第二步开启 NDJSON 选项NDJSON 的开关在 JsonDocumentOptions 里只需打开一个属性var options new JsonDocumentOptions { UseNewlineDelimitedFormat true // 告诉解析器以换行符切分 };第三步await foreach逐行处理await using var stream File.OpenRead(events.ndjson); await foreach (var record in JsonSequence.DeserializeAsyncEventRecord(stream, options: options, cancellationToken: ct)) { if (record is null) continue; Process(record); // 每处理完一条即可释放不累积 }整个过程只有一小段代码却能处理任意大小的.ndjson文件。官方测试 JsonSequenceTest.cs 中就用 3000 行的 NDJSON 流验证了逐行反序列化而 SequenceParse.cs 演示了与System.Text.Json的DeserializeAsyncEnumerable对等的用法。内存骤降的真相它到底省在哪翻开 JsonSequence.cs 的实现可以看到三个关键的省内存设计固定小缓冲滚动读取内部通过ArrayPoolbyte租用缓冲默认 16 KB见 SerializerSettings.cs 的DefaultBufferSize读完一段就Compact前移、继续读下一段——文件永远只有 16 KB 左右驻留在内存。缓冲不足时按 2 倍扩租用后即归还对象池。解析文档被复用每个元素解析后内部文档document被循环重用通过InstanceCache不会为每一行新建一棵 DOM 树。零额外拷贝的换行扫描NDJSON 模式下内置Scanner.ScanNewline直接在字节缓冲上定位行边界连正则都不需要。对比之下JsonDocument.Parse(File.ReadAllText(...))至少产生「文件字节 字符串 文档树」三份副本。逐行流式解析把这三份副本压缩成了「一小块缓冲 一个复用文档」这就是内存占用骤降的来源。⚠️一个小注意点ParseAsync产出的DElement背后是复用文档只在当次迭代有效。如果需要跨迭代保留比如收集所有 error 级别的事件请调用element.Clone()或先用ToT()转成对象。大 JSON 数组也能「流式」解析如果你的大文件是一个顶层数组比如[{level:info,...}, ...]不需要开启 NDJSON 选项直接用默认的ParseAsync即可——扫描器会跟踪括号深度在顶层逗号处把数组切段一段一段解析产出await using var stream File.OpenRead(events.json); // 顶层数组可达 GB 级 await foreach (var element in JsonSequence.ParseAsync(stream, cancellationToken: ct)) { if (element.TryGetProperty(level, out var level) level.GetString() error) { errors.Add(element.Clone()); // 需要保留时才克隆 } }这个技巧意味着哪怕上游系统只能给你「一整个巨大 JSON 数组」你同样可以享受逐元素流式处理的低内存优势。生产环境实用细节可取消两个 API 都接受CancellationToken且每次迭代都会检查取消长任务可随时中断UTF-8 BOM 自动识别流开头的 BOM 会被自动剥离见ParseAsync中的 BOM 检查逻辑测试 JsonSequenceTest.cs 覆盖了带 BOM 的根数组与 NDJSON空行、缩进不敏感NDJSON 解析会自动跳过空白行{a:1} \n\t{a:2}这类不规整输入也没问题见 JsonNDJsonTest.cs性能可复现基准测试 JsonSequenceDeserialize.cs 用[MemoryDiagnoser]同时测量耗时与分配量覆盖 1,000 / 100,000 条记录可对比System.Text.Json的DeserializeAsyncEnumerable与整数组反序列化dotnet run -c Release --project benchmarks/REDox.Json.Benchmarks总结大文件 JSON 流式解析的选型建议场景推荐方式NDJSON 日志 / 事件流JsonSequence.DeserializeAsyncTUseNewlineDelimitedFormat巨型顶层数组文件JsonSequence.ParseAsync默认模式需要保留中间结果对DElement调用Clone()或ToT()追求极致对象吞吐基准项目里对比 REDox 与 STJ 后自行验证REDox的 token DOM 架构让「流式」与「高性能」不再二选一JsonSequence用 16 KB 的滚动缓冲支撑 GB 级 NDJSON 的逐行异步解析让 .NET 开发者第一次能像处理 CSV 那样轻松处理大 JSON 文件。延伸阅读核心实现JsonSequence.cs选项定义JsonDocumentOptions.cs序列化设置缓冲区大小SerializerSettings.cs流式解析测试JsonSequenceTest.cs、JsonNDJsonTest.csNDJSON 编码/解析回归测试JsonNDJsonTest.cs基准测试JsonSequenceDeserialize.cs项目总览README.md【免费下载链接】REDoxHigh-performance, token-based structured data engine for .NET. A core component of REX, the technology behind CAPCOMs next-generation game engine.项目地址: https://gitcode.com/gh_mirrors/redox/REDox创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表