如何提升循环内多次JsonConvert反序列化操作的性能?
嘿,这个场景我太熟了——循环里反复调用JsonConvert.DeserializeObject确实容易拖慢性能,尤其是当jsonItems数量多的时候。下面几个实用的办法,应该能帮你显著提升速度:
1. 复用JsonSerializer实例(Newtonsoft.Json)
每次调用JsonConvert.DeserializeObject,底层都会新建一个JsonSerializer实例,这在循环里会产生大量不必要的初始化开销。我们可以提前创建好序列化器,在循环里反复复用:
// 提前初始化序列化器,有自定义配置的话在这里设置 var serializer = JsonSerializer.CreateDefault(); foreach (var mainItem in jsonItems) { // 使用StringReader和JsonTextReader配合序列化器反序列化 using (var stringReader = new StringReader(mainItem.JsonString)) using (var jsonReader = new JsonTextReader(stringReader)) { var items = serializer.Deserialize<List<MainGridViewClass>>(jsonReader); foreach (var item in items) { // 你的业务操作 } } }
这个改动的性能提升非常明显,尤其是循环次数超过几百次的时候——相当于把重复的初始化工作只做了一次。
2. 批量反序列化(如果业务允许)
如果每个mainItem.JsonString都是独立的数组JSON,那可以考虑把所有字符串拼接成一个大数组,一次性完成反序列化,减少多次反序列化的开销:
// 拼接所有子数组为一个大JSON数组(注意确保每个子JSON格式合法) var combinedJson = $"[{string.Join(",", jsonItems.Select(m => m.JsonString))}]"; var allItemLists = JsonConvert.DeserializeObject<List<List<MainGridViewClass>>>(combinedJson); foreach (var items in allItemLists) { foreach (var item in items) { // 你的业务操作 } }
这种方式直接把多次反序列化变成一次,性能提升幅度最大,但前提是你能保证拼接后的JSON是合法的——比如每个子JSON本身就是数组,没有语法错误。
3. 切换到更高效的JSON库:System.Text.Json
如果你用的是.NET Core 3.0+或.NET 5+,官方内置的System.Text.Json性能普遍优于Newtonsoft.Json,尤其是在大量反序列化的场景下。切换的成本也不高:
// 提前创建配置选项,复用它(避免每次初始化) var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true // 按需配置,比如忽略大小写匹配属性 }; foreach (var mainItem in jsonItems) { var items = JsonSerializer.Deserialize<List<MainGridViewClass>>(mainItem.JsonString, options); foreach (var item in items) { // 你的业务操作 } }
注意System.Text.Json的默认行为和Newtonsoft.Json略有不同(比如默认大小写敏感),需要根据你的类型结构调整配置,但性能收益值得这个小成本。
4. 缓存类型契约(进阶优化)
Newtonsoft.Json会自动缓存类型的序列化契约,但如果你的MainGridViewClass结构非常复杂,或者动态生成的话,可以提前手动生成契约并缓存,进一步减少开销:
// 提前缓存类型契约 var contract = JsonSerializer.CreateDefault().ContractResolver.ResolveContract(typeof(List<MainGridViewClass>)) as JsonArrayContract; var serializer = new JsonSerializer { ContractResolver = new DefaultContractResolver() }; foreach (var mainItem in jsonItems) { using (var stringReader = new StringReader(mainItem.JsonString)) using (var jsonReader = new JsonTextReader(stringReader)) { var items = (List<MainGridViewClass>)serializer.Deserialize(jsonReader, contract.UnderlyingType); foreach (var item in items) { // 你的业务操作 } } }
这个优化的收益相对小一些,适合极端性能要求的场景,一般情况下前面几个方法就足够了。
内容的提问来源于stack exchange,提问作者George

