使用巨大的 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 反序列化的主要内容,如果未能解决你的问题,请参考以下文章