【问题标题】:What is better to use when parsing dynamic JSON data: JToken or c# built in dynamic type解析动态JSON数据时用什么比较好:JToken或者c#内置动态类型
【发布时间】:2017-07-14 03:02:18
【问题描述】:

搜索互联网时找不到任何正确答案...

我从服务器收到了JSON 数据。它的格式每次都可能不同,所以我必须使用动态对象。目前在我们的项目中,我们正在使用来自Newtonsoft.JSON 库的JToken 类型,但是如果我们看看它的内部结构......恐怕它有很多不好的装箱/拆箱案例 - 我们应该使用尽可能少的内存,因为它是一个移动应用程序。

所以问题是:使用来自c# 本身的dynamic 类型会更好(是的,尽管也有装箱/拆箱)还是它们之间没有区别?它们在内存使用方面的表现如何?有没有人对它们进行过一些基准测试?

也许他们两个都有不错的选择?

提前致谢

【问题讨论】:

  • 与 c# 的动态库相比,大多数在线回复更喜欢 Newtonsoft.JSON。虽然,这只能由设计者决定好坏。您是否尝试过进行任何测试以确定差异是否值得研究?
  • 响应的可变性如何?它主要是通过一些可能的附加属性来固定的,还是完全可变的?
  • @vipersassassin 不幸的是,我认为我应该这样做。我想也许社区中的某个人已经做过或类似的事情
  • @dbc,它完全是动态的。如果它是静态类型,我会使用自定义类型:)
  • @Andrew 我已经阅读了一些与这个问题相关的项目,尽管它们似乎都没有特别回答你的问题。似乎两者在本质上被认为是相同的,并且完全由设计师来确定最适合他们的流程。

标签: c# json dynamic json.net


【解决方案1】:

所以似乎没有人做过与我的问题相关的事情,我已经进行了自己的测试,现在我不想分享我的结果。希望他们真的很有帮助。

起初我想说我对一些结果感到非常震惊和惊讶。

首先是我的测试机配置:

  • 配备 2.40 GHz 英特尔酷睿 i5-6200 CPU 的 HP Probook 450 G3 笔记本电脑
  • 8 GB 内存
  • 256MB SSD Patriot Ignite M2,高达 560MB/s 读取和 320MB/s 写入 IO
  • 希捷 1000 GB SATA 硬盘
  • Windows 10 专业版 x64 操作系统

测试非常简单:有一个 json 字符串,它的大小存储在一个 4.54 kB 的文件中。我运行 100 个测试,每个测试创建 1000 个指定类型的对象(动态/JToken/JContainer)。在每次测试期间,我都会计算分配这 1000 个对象的实际内存量以及将 json-string 解析为指定对象类型所需的时间。完成所有测试后,我计算每个测试集的平均已用内存量和平均时间。通过基于公式for 0 < i < n, S += SUM(i), a = S/n 的简单算法计算的平均计数器,其中S - 所有计数器的总和,n - 测试数量 (100),a - 平均计数器。内存使用由ProcessGC 统计

现在最有趣的部分 (IMO) - 我的基准测试结果 :)

首先我使用Newtonsoft.JSON 内置方法JToken.Parse()JContainer.Parse() 运行测试。这两个集合都产生了与预期相同的结果(因为JContainer 是来自JToken 的嵌套类型):

JToken/JContainer

平均内存使用:25.7 MB

平均解析时间:223 毫秒

很简单。现在我使用 JsonConver.Deserialize<T>(string json) 方法运行测试,将我的 json 数据反序列化为相同的 JToken/JContainer 类型,我有点惊讶

JsonConver.Deserialize(string json) 到 JToken/JContainer

平均内存使用量:22.0 MB

平均解析时间:223 毫秒

所以,就我个人而言,Parse() 方法为JToken/JContainer 生成的对象分配的内存比使用JsonConver.Deserialize<T>() 方法时要多,这有点令人惊讶。真是出乎意料。

这部分的最后一组测试是dynamic类型使用相同的JsonConver.Deserialize<T>(string json)方法:

JsonConver.Deserialize(string json) 转为动态

平均内存使用:22.1 MB

平均解析时间:224 毫秒

老实说,我期待一些不同的结果,但似乎 JToken 只是 dynamic 的包装,这就是为什么他们使用相同的内存量并花费相同的解析时间。

所有事情都可以是好的和足够的,但总是有一些“但是”的条件。我用于测试的 json 数据很小(当然,我们总是尝试通过网络发送尽可能少的数据)。我必须使用的真实对象实例具有更大的大小,并且为了对我的真实数据真正满意,我运行了另一个测试集。现在,大小为 270 kB 的真实对象(与第一组的 4.54 kB 相比)。结果真的让我很震惊。 JToken/JContainerParse() 方法失败!!!我的 8 GB RAM 机器上出现内存不足异常!!!在我附近打开任务管理器后,我看到我的测试程序的内存超过 2 GB !!!我以为这就是我的测试的结束,但我是个雄心勃勃的人,所以我继续。使用JsonConver.Deserialize<T>() 运行测试让我在这方面取得了更大的成功:

270kBs JsonConver.Deserialize()

平均内存使用:1.63 GB

平均解析时间:20 秒

是的,确实如此:将 1000 个对象解析为 JToken/JContainer 类型需要 1.63 GB 和 20 秒。使用dynamic 给了我相同的结果,所以我不会再次复制它们

如果我没有尝试使用对象解析测试我的 json,这些测试将不完整。所以我创建了一个类来描述我的 json 结构并使用JsonConver.Deserialize<T>() 方法:

JsonConver.Deserialize() 解析为 POCO 对象

平均内存使用:72 MB

平均解析时间:7.5。 s

1000 个 POCO 对象为 72 MB,而动态数据为 1.63 Gbs。

附言。而不是结论......当然,我们总是尝试使用对象来处理代码中的数据,但有时我们必须处理动态。现在您可以看到 C# 中的对象是多么高效。此外,我建议你永远不要使用JToken.Parse(),为自己节省一点内存。而 IMO,OOP 的引入是为了真正帮助开发人员并使我们的夜梦变得美好。它的工作! :)

PPS。所有有兴趣查看我的测试解决方案的人-欢迎github :)

【讨论】:

    猜你喜欢
    • 2021-12-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-18
    • 1970-01-01
    • 2012-04-29
    • 2019-12-01
    相关资源
    最近更新 更多