首页 新闻 会员 周边 捐助

.net core 下的json库Newtonsoft.Json,在程序运行一段时间后了,序列化反序列化时间越来越长

0
悬赏园豆:100 [已解决问题] 解决于 2019-08-09 09:39

前两个星期公司系统从.net framwork升级到了.net core 2.2,被客户投诉系统变慢,刚开始我们把问题归咎于数据库驱动,还在园子里面发博问求助,主要是因为自己看到一些文章说过数据库驱动的问题,而且我们监控打点的地方不是直接在只访问数据库的点,还包含了json反序列化,所以先入为主的把问题直接定位在了数据库驱动,后来发现,程序运行一段时间后,那些没有访问数据库的地方也变慢,直接看代码发现,特殊的地方就是里面用了json反序列化。果然,在程序启动一段时间,json反序列化性能没有任何问题,序列化一个比较大的对象也就几毫秒,甚至不到1毫秒。运行一段时间后,继续监控,开始出现几十毫秒。直到发现访问越来越慢,json反序列化居然差不多要1秒。

图1,是程序刚开始启动,图2,是很慢的时候。

图1

图2

至此,可以说终于找到问题的根本原因了,接下来是找到办法解决这个问题了,针对这种情况,不知道大家是怎么解决的?

我们是想尝试升级到.net core 3.0,使用内置json库,但是看了dudu大佬提的这个博问,这个库好像序列化中文是编码过的,不知道最后解决了没有?

问题补充:

我们引用的Newtonsoft.Json库版本为12.0.1

Alan_Liu的主页 Alan_Liu | 初学一级 | 园豆:61
提问于:2019-08-08 09:25

图裂 重新修改下

winds_随风 5年前

@winds_随风: 改了,可以吗

Alan_Liu 5年前
< >
分享
最佳答案
1

果然还是我们自己使用的问题,我们在应用启动的时候设置了一个全局的Setting:

var setting = new Newtonsoft.Json.JsonSerializerSettings();
Newtonsoft.Json.JsonConvert.DefaultSettings = new Func<Newtonsoft.Json.JsonSerializerSettings>(() =>
{
       setting.NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore;
                
       setting.Converters.Add(new GuidJsonConverter());

       return setting;
 });

就是上面代码setting.Converters.Add(new GuidJsonConverter()) 的这一设置导致应用跑着跑着,序列化反序列化越来越慢,这一段代码根本没什么用,里面是解决读取json字符串时,解析那些不是合法的Guid的转换问题,而且里面居然用了正则去判断,前端传过来的Guid不合法,在后端解决,这也是一种奇葩的解决方案!把这段代码注释掉之后,到目前为止,再也没有出现序列化反序列化慢的问题了。

Alan_Liu | 初学一级 |园豆:61 | 2019-08-09 09:37

为什么一开始不慢呢?很奇怪这个convert做了什么还有累积效应。

Timetombs | 园豆:3959 (老鸟四级) | 2019-08-09 09:50

恭喜啊。不过有一点不同意你的观点。前端需要判断是否合法,后端也需要判断的,前端比较容易越过判断,双重判断比较保险。

会长 | 园豆:12463 (专家六级) | 2019-08-09 09:50

@会长: 我们前端同事使用ext框架,生成的Id都是ext-xxx的id,后端实体类对应的属性类型为Guid,所有反序列化提交的数据就出错了,后来为了处理这个id,专门写了这个类去解决,如果我们实体类是的属性是Guid?可为空的Guid就不会。

Alan_Liu | 园豆:61 (初学一级) | 2019-08-09 13:05

这种同事 改打死 2333

winds_随风 | 园豆:156 (初学一级) | 2019-08-09 15:15
其他回答(2)
0

我写了一段代码运行需要11秒(我的电脑比较老旧了),没有你说的那么慢,可否写个能重现问题的demo发上来?这是我写的:

using Newtonsoft.Json;
using System;
using System.Diagnostics;

namespace JsonTest
{
    class Program
    {
        static void Main(string[] args)
        {
            var wang = new Person
            {
                Name = "老王",
                Age = 35,
                Gender = "男",
                Degree = "本科",
                Address = "北京市海淀区东北旺中路菊园小区2号楼2单元302"
            };

            string json = JsonConvert.SerializeObject(wang);

            Stopwatch watch = new Stopwatch();
            watch.Start();

            for (int i = 0; i < 2000000; i++)
            {
                var copyWang = JsonConvert.DeserializeObject<Person>(json);
            }

            watch.Stop();
            Console.WriteLine(watch.ElapsedMilliseconds / 1000); // 11
            Console.ReadLine();
        }
    }

    class Person
    {
        public string Name { get; set; }

        public int Age { get; set; }

        public string Gender { get; set; }

        public string Degree { get; set; }

        public string Address { get; set; }
    }
}

我的版本:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp2.2</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
  </ItemGroup>

</Project>

我还怀疑你们是不是有什么的地方比较耗cpu或者内存,是不是因为运行的时间久了把服务器的资源耗尽了,所以变慢了?

收获园豆:50
会长 | 园豆:12463 (专家六级) | 2019-08-08 10:33

这是我们反序列化的代码(上面deserializeObject部分):

var sw = new System.Diagnostics.Stopwatch();
sw.Start();
var systemFuncMenus = JsonConvert.DeserializeObject<List<systemFuncMenu>>(jsonArrayText);
sw.Stop();

jsonArrayText的字符串比较大,有将近10k,开始启动我们也很快啊,但是运行了几个小时后,就出现上面说的反序列化要那么长时间,在系统慢的时候,我看cpu、内存、线程数都正常的,我从负载均衡移除了,cpu 0,内存500多M,线程数 80多,跟启动差不多,然后就在这台机测试,还是慢,每一个调试都慢。我们系统是To B的,很多接口返回的数据都比较大。

这是2019-8-8 11:10分,我从负载均衡移除了这台机,等了一段时间后,再在这台机内部调用上面那段代码的接口:
在这里插入图片描述

支持(0) 反对(0) Alan_Liu | 园豆:61 (初学一级) | 2019-08-08 10:48

@Alan_Liu: 你有没有单独写一个demo?看问题能重现不,如果能说明类库有问题,如果不能说明其它的地方有问题。

支持(0) 反对(0) 会长 | 园豆:12463 (专家六级) | 2019-08-08 11:16

@Alan_Liu: 如果实在不行,换一个其它库试试,又不是只有这一个

支持(0) 反对(0) 会长 | 园豆:12463 (专家六级) | 2019-08-08 11:34

@会长: 嗯,我专门写个控制台,只执行上面那段代码试试

支持(0) 反对(0) Alan_Liu | 园豆:61 (初学一级) | 2019-08-08 11:35

@会长: 好的,我现在不能100%确定是不是它的问题,还是我们使用有问题,但是反序列化是调用这个接口JsonConvert.DeserializeObject没错吧

支持(0) 反对(0) Alan_Liu | 园豆:61 (初学一级) | 2019-08-08 11:38

@Alan_Liu: 应该没错,官网上的实例就是掉的这个了

支持(0) 反对(0) 会长 | 园豆:12463 (专家六级) | 2019-08-08 11:39
0

是不是累计的json处理导致了gc的问题?我记得3.0 有dotnet-counters 和dotnet-dump工具可以用了,不知道2.2环境能用不。https://github.com/dotnet/diagnostics

收获园豆:50
Timetombs | 园豆:3959 (老鸟四级) | 2019-08-08 11:59

好的,我研究一下

支持(0) 反对(0) Alan_Liu | 园豆:61 (初学一级) | 2019-08-08 12:05
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册