一尘不染

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

redis

我正在使用Go,Revel WAF和Redis。

我必须在Redis中存储大型json数据(可能为20MB)。

json.Unmarshal()大约需要5秒钟。有什么更好的方法呢?

我尝试了JsonLib,encode / json,ffjson,megajson,但是它们都不够快。

我曾考虑过使用groupcache,但是Json是实时更新的。

这是示例代码:

package main

import (
 "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!!!
}

阅读 439

收藏
2020-06-20

共1个答案

一尘不染

解析大型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毫秒:
十分之一

您的结果会有所不同,具体取决于您那里实际有多少个浮标。如果您的float的有效位数很多,应使用其float64表示形式,那么20
MB的JSON包含的内容将远远少于我的200万个float。在这种情况下,JSON和GOB之间的差异将更加明显。

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

如果发送者和解析器都不都是Go,或者如果您想进一步降低性能,则应该使用自己的自定义二进制格式,或者使用协议缓冲区,或者手动使用“ encoding /
binary”和其好友。

2020-06-20