使用巨大的 int JSON 数组更快地进行 JSON 反序列化

Posted

技术标签:

【中文标题】使用巨大的 int JSON 数组更快地进行 JSON 反序列化【英文标题】:Faster JSON deserialization with huge int JSON array 【发布时间】:2021-08-28 06:21:19 【问题描述】:

我必须在 android 中反序列化一个 Json 对象,其中包含一个巨大的 Int Json 数组。

架构是这样的:

 
   "key1": "value1",
   "key2": "value2",
   "smallObject": 
      "key": "value"
   ,
   "smallArray" [
      ,  ,
   ],
   "hugeObject": 
      "data": 
          "hugeIntArray": [
              -1, -1, 1, 2, -1 ...
          ]
      ,
      "key": "value"
   

hugeIntArray数组的长度可以超过200万,使得JSON文件大于15MB。

我尝试用 Gson 解析,需要 7 秒,还有 Moshi,需要 11 秒。

我发现 Moshi 可以通过自定义 JsonAdapter 和序列进行延迟加载。但我无法将它应用到我的架构中。

我的目标是像序列或流一样使用它来将 int 值转换为图像的像素。

【问题讨论】:

没有一个好的答案,因为你使用了错误的工具。不要像那样使用二进制数据序列化/反序列化:它会浪费流量和资源。我猜你至少需要一个字节数组(我猜你的 int 数组不会有非字节值)。提前知道字节数组的长度会非常好,通过添加诸如hugeIntArrayLength/hugeByteArrayLength之类的东西来减少中间数组分配的数量(否则Gson或Moshi怎么能提前知道最终长度?)。 在 JSON 中打包二进制数据通常是一个坏主意,有更多不这样​​做的原因。即使按照下面的建议将其编码为 Base64 编码的字符串也是一个坏主意:读取巨大的字符串会使您的设备承受中间对象分配的压力。另一件事是,如果您使用的是 Web 套接字,则 WS 使用者应该只使用消息(可能尽可能快:不建议使用巨大的数组)。 这里最好的选择是完全拒绝像JSON那样发送二进制数据的想法,而是放置引用二进制数据的资源URL而不是巨大的数组,并且仅在确实需要时才加载此类资源.结果:您的应用将使用更少的内存,从 Gson/Moshi 的角度来看,它会运行得更快,它会按需加载链接的资源(可能以优化的方式)等等。 【参考方案1】:

在这种情况下有什么方法可以避免使用 Json 吗?数据确实应该是二进制格式

【讨论】:

感谢您的建议。有一个 websocket 通过回调 fun onMessage(conn: WebSocket, message: String) 不断向 Android 发送消息 在当前约定下,消息具有 JSON 模式,因此我可以解析其消息类型/uri 和重置有效负载以做进一步的事情。 用包含数组二进制表示的 base64 字符串替换 hugeIntArray 怎么样?如果已知每个 int 都是一个小数,这将特别有用。如果是这样,您可以将其中的几个压缩到一个字节中。它仍然是 Json 您好,感谢您的建议。我压缩了hugeIntArray,用Base64 -> Gzip -> Base64,现在它是一个长度为10%的字符串,JSON文件从15 MB减少到0.6 MB,解析速度只有毫秒。【参考方案2】:

你试过JsonReader吗?它专门用于将 json 文件作为流读取

【讨论】:

是的。正如我从 Moshi 看到的,它使用带有 moshi JsonReader 的 JsonAdapter 来解析任何 JSON。如果我使用默认的 Moshi 设置,它会生成一个如下所示的适配器来解析该字段。 hugeIntArray = listOfIntAdapter.fromJson(reader) ?: throw Util.unexpectedNull("hugeIntArray", "hugeIntArray", reader) 它最终很慢。我认为它可能与 Android JsonReader 类似。

以上是关于使用巨大的 int JSON 数组更快地进行 JSON 反序列化的主要内容,如果未能解决你的问题,请参考以下文章

在 Python 中对单个数组进行更快的双重迭代

C#以int数组为索引过滤for循环的更快方法?

使用swift解码巨大的JSON数组URL

将巨大的(95Mb)JSON 数组拆分成更小的块?

在 INTARRAY 列中更快地搜索

我可以通过使用多个线程来更快地分配内存吗?