为了账号安全,请及时绑定邮箱和手机立即绑定

Go JSON 解码非常慢。什么是更好的方法呢?

Go JSON 解码非常慢。什么是更好的方法呢?

Go
慕田峪7331174 2021-09-27 10:56:13
我正在使用 Go、Revel WAF 和 Redis。我必须在 Redis 中存储大型 json 数据(可能是 20MB)。json.Unmarshal()大约需要 5 秒钟。什么是更好的方法呢?我尝试了 JsonLib、encode/json、ffjson、megajson,但它们都不够快。想过用groupcache,但是Json是实时更新的。这是示例代码:package mainimport ( "github.com/garyburd/redigo/redis"  json "github.com/pquerna/ffjson/ffjson")func main() {  c, err := redis.Dial("tcp", ":6379")  defer c.Close()  pointTable, err := redis.String(c.Do("GET", "data"))  var hashPoint map[string][]float64  json.Unmarshal([]byte(pointTable), &hashPoint) //Problem!!!}
查看完整描述

3 回答

?
呼唤远方

TA贡献1856条经验 获得超11个赞

解析大型 JSON 数据似乎比它应该的要慢。查明原因并向 Go 作者提交补丁是值得的。

同时,如果你能避免使用JSON并使用二进制格式,你不仅可以避免这个问题;您还将获得代码现在花费的时间将数字的 ASCII 十进制表示解析为它们的二进制 IEEE 754 等效项(并且在这样做时可能会引入舍入错误。)

如果您的发送方和接收方都是用 Go 编写的,我建议使用 Go 的二进制格式:gob

做一个快速测试,生成一个包含 2000 个条目的地图,每个条目有 1050 个简单浮点数,给我 20 MB 的 JSON,在我的机器上解析需要 1.16 秒。

对于这些快速基准测试,我采用了三个运行中的最佳值,但我确保只测量实际解析时间,t0 := time.Now()在 Unmarshal 调用之前和time.Now().Sub(t0)之后打印。

使用 GOB,相同的地图产生 18 MB 的数据,解析需要 115 毫秒:
时间的十分之一

您的结果将根据您在那里拥有的实际浮点数而有所不同。如果你的浮点数有很多有效数字,值得他们用 float64 表示,那么 20 MB 的 JSON 将比我的 200 万个浮点数少得多。在这种情况下,JSON 和 GOB 之间的区别将变得更加明显。

顺便说一句,这证明问题确实在于 JSON 解析器,而不是要解析的数据量,也不在于要创建的内存结构(因为两个测试都在解析 ~ 20 MB 的数据并重新创建相同的浮点数切片。)用 JSON 中的字符串替换所有浮点数给了我 1.02 秒的解析时间,确认从字符串表示到二进制浮点数的转换确实需要一定时间(与仅移动字节相比)但不是主要的罪魁祸首。

如果发送方和解析器都不是 Go,或者如果你想比 GOB 更进一步地压缩性能,你应该使用你自己定制的二进制格式,要么使用协议缓冲区,要么手动使用“编码/二进制”和朋友。


查看完整回答
反对 回复 2021-09-27
?
料青山看我应如是

TA贡献1772条经验 获得超8个赞

试试fastjson。它针对速度进行了优化,并且与标准encoding/json. 此外,fastjson不需要遵循 JSON 模式的结构 - 单个解析器可以解析具有不同模式的多个 JSON。


查看完整回答
反对 回复 2021-09-27
  • 3 回答
  • 0 关注
  • 428 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信