gpt4 book ai didi

c# - JSON.NET ANY ContractResolver 导致性能不佳

转载 作者:行者123 更新时间:2023-11-30 15:53:55 25 4
gpt4 key购买 nike

在对吞吐量非常高的应用程序进行性能测试时,我们发现 JSON.NET 的 ContractResolver 存在问题。不幸的是,当您指定 ContractResolver 时,性能变得难以忍受,包括 DefaultContractResolver

寻求其他专家的建议,了解有关如何提高性能而不锁定 CPU 和占用不合理时间的任何建议。现在,由于这个问题,我们发现性能降低了 87%(定义任何 ContractResolver 时每秒 80 个请求,没有定义 ContractResolver 时每秒 600 个请求定义。

测试运行的输出是:

默认解析器:耗时 3736 毫秒

NoOp 解析器:耗时 4150 毫秒

无解析器:已用 8 毫秒

SnakeCase:耗时 4753 毫秒

第三方 (SnakeCase.JsonNet):耗时 3881 毫秒

强调这一点的测试如下:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using SnakeCase.JsonNet;

namespace Anonymous.Public.Namespace
{
public class Person
{
public string Name { get; set; }
public DateTime DateOfBirth { get; set; }
public bool EatsMeat { get; set; }
public decimal YearlyHouseholdIncome { get; set; }

public List<Car> CarList { get; set; }
}

public class Car
{
public string Make { get; set; }
public string Model { get; set; }
public int Year { get; set; }
}

public class NoOpNamingStrategy : NamingStrategy
{
public NoOpNamingStrategy(bool processDictionaryKeys, bool overrideSpecifiedNames)
{
base.ProcessDictionaryKeys = processDictionaryKeys;
base.OverrideSpecifiedNames = overrideSpecifiedNames;
}

public NoOpNamingStrategy(bool processDictionaryKeys, bool overrideSpecifiedNames, bool processExtensionDataNames) : this(processDictionaryKeys, overrideSpecifiedNames)
{
base.ProcessExtensionDataNames = processExtensionDataNames;
}

public NoOpNamingStrategy()
{
}

protected override string ResolvePropertyName(string name)
{
return name;
}
}

[TestClass]
public class SerializationTest
{
public static Person p { get; set; } = new Person
{
Name = "Foo Bar",
DateOfBirth = new DateTime(1970, 01, 01),
EatsMeat = true,
YearlyHouseholdIncome = 47333M,
CarList = new List<Car>
{
new Car
{
Make = "Honda",
Model = "Civic",
Year = 2019
}
}
};

public const int ITERATIONS = 1000;

[TestMethod]
public void TestSnakeCase()
{
var sw = new Stopwatch();
sw.Start();
for (var i = 0; i < ITERATIONS; i++)
{
var str = JsonConvert.SerializeObject(p, new JsonSerializerSettings
{
ContractResolver = new DefaultContractResolver
{
NamingStrategy = new SnakeCaseNamingStrategy()
}
});
}

sw.Stop();
var elapsed = sw.ElapsedMilliseconds;
Debug.WriteLine($"Time elapsed {elapsed} milliseconds");
}

[TestMethod]
public void TestNoResolver()
{
var sw = new Stopwatch();
sw.Start();
for (var i = 0; i < ITERATIONS; i++)
{
var str = JsonConvert.SerializeObject(p);
}

sw.Stop();
var elapsed = sw.ElapsedMilliseconds;
Debug.WriteLine($"Time elapsed {elapsed} milliseconds");
}

[TestMethod]
public void TestDefaultResolver()
{
var sw = new Stopwatch();
sw.Start();
for (var i = 0; i < ITERATIONS; i++)
{
var str = JsonConvert.SerializeObject(p, new JsonSerializerSettings
{
ContractResolver = new DefaultContractResolver()
});
}

sw.Stop();
var elapsed = sw.ElapsedMilliseconds;
Debug.WriteLine($"Time elapsed {elapsed} milliseconds");
}

[TestMethod]
public void TestThirdPartySnakeResolver()
{
var sw = new Stopwatch();
sw.Start();
for (var i = 0; i < ITERATIONS; i++)
{
var str = JsonConvert.SerializeObject(p, new JsonSerializerSettings
{
ContractResolver = new SnakeCaseContractResolver()
});
}

sw.Stop();
var elapsed = sw.ElapsedMilliseconds;
Debug.WriteLine($"Time elapsed {elapsed} milliseconds");
}

[TestMethod]
public void TestNoOpResolver()
{
var sw = new Stopwatch();
sw.Start();
for (var i = 0; i < ITERATIONS; i++)
{
var str = JsonConvert.SerializeObject(p, new JsonSerializerSettings
{
ContractResolver = new DefaultContractResolver
{
NamingStrategy = new NoOpNamingStrategy()
}
});
}

sw.Stop();
var elapsed = sw.ElapsedMilliseconds;
Debug.WriteLine($"Time elapsed {elapsed} milliseconds");
}
}
}

最佳答案

看起来好像 ContractResolver 需要反射,如果保留的话将缓存对象类型。在全局范围内存储 ContractResolver 会大大改变时间:

默认解析器:耗时 10 毫秒

NoOp 解析器:7 毫秒过去的时间

无解析器:耗时 7 毫秒

SnakeCase:耗时 178 毫秒

第三方 (SnakeCase.JsonNet):耗时 10 毫秒

更新的测试代码:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using SnakeCase.JsonNet;

namespace Anonymous.Public.Namespace
{
public class Person
{
public string Name { get; set; }
public DateTime DateOfBirth { get; set; }
public bool EatsMeat { get; set; }
public decimal YearlyHouseholdIncome { get; set; }

public List<Car> CarList { get; set; }
}

public class Car
{
public string Make { get; set; }
public string Model { get; set; }
public int Year { get; set; }
}
public class NoOpNamingStrategy : NamingStrategy
{
public NoOpNamingStrategy(bool processDictionaryKeys, bool overrideSpecifiedNames)
{
base.ProcessDictionaryKeys = processDictionaryKeys;
base.OverrideSpecifiedNames = overrideSpecifiedNames;
}

public NoOpNamingStrategy(bool processDictionaryKeys, bool overrideSpecifiedNames, bool processExtensionDataNames) : this(processDictionaryKeys, overrideSpecifiedNames)
{
base.ProcessExtensionDataNames = processExtensionDataNames;
}

public NoOpNamingStrategy()
{
}

protected override string ResolvePropertyName(string name)
{
return name;
}
}

[TestClass]
public class SerializationTest
{
public static Person p { get; set; } = new Person
{
Name = "Foo Bar",
DateOfBirth = new DateTime(1970, 01, 01),
EatsMeat = true,
YearlyHouseholdIncome = 47333M,
CarList = new List<Car>
{
new Car
{
Make = "Honda",
Model = "Civic",
Year = 2019
}
}
};

public static IContractResolver Default { get; set; } = new DefaultContractResolver();

public static IContractResolver NoOp { get; set; } = new DefaultContractResolver
{
NamingStrategy = new NoOpNamingStrategy()
};

public static IContractResolver SnakeCase { get; set; } = new DefaultContractResolver
{
NamingStrategy = new SnakeCaseNamingStrategy()
};

public static IContractResolver ThirdParty { get; set; } = new SnakeCaseContractResolver();

public const int ITERATIONS = 1000;

[TestMethod]
public void TestSnakeCase()
{
var sw = new Stopwatch();
sw.Start();
for (var i = 0; i < ITERATIONS; i++)
{
var str = JsonConvert.SerializeObject(p, new JsonSerializerSettings
{
ContractResolver = SnakeCase
});
}

sw.Stop();
var elapsed = sw.ElapsedMilliseconds;
Debug.WriteLine($"Time elapsed {elapsed} milliseconds");
}

[TestMethod]
public void TestNoResolver()
{
var sw = new Stopwatch();
sw.Start();
for (var i = 0; i < ITERATIONS; i++)
{
var str = JsonConvert.SerializeObject(p);
}

sw.Stop();
var elapsed = sw.ElapsedMilliseconds;
Debug.WriteLine($"Time elapsed {elapsed} milliseconds");
}

[TestMethod]
public void TestDefaultResolver()
{
var sw = new Stopwatch();
sw.Start();
for (var i = 0; i < ITERATIONS; i++)
{
var str = JsonConvert.SerializeObject(p, new JsonSerializerSettings
{
ContractResolver = Default
});
}

sw.Stop();
var elapsed = sw.ElapsedMilliseconds;
Debug.WriteLine($"Time elapsed {elapsed} milliseconds");
}

[TestMethod]
public void TestThirdPartySnakeResolver()
{
var sw = new Stopwatch();
sw.Start();
for (var i = 0; i < ITERATIONS; i++)
{
var str = JsonConvert.SerializeObject(p, new JsonSerializerSettings
{
ContractResolver = ThirdParty
});
}

sw.Stop();
var elapsed = sw.ElapsedMilliseconds;
Debug.WriteLine($"Time elapsed {elapsed} milliseconds");
}

[TestMethod]
public void TestNoOpResolver()
{
var sw = new Stopwatch();
sw.Start();
for (var i = 0; i < ITERATIONS; i++)
{
var str = JsonConvert.SerializeObject(p, new JsonSerializerSettings
{
ContractResolver = NoOp
});
}

sw.Stop();
var elapsed = sw.ElapsedMilliseconds;
Debug.WriteLine($"Time elapsed {elapsed} milliseconds");
}
}
}

关于c# - JSON.NET ANY ContractResolver 导致性能不佳,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51603054/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com