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

Go JSON解码非常慢。有什么更好的方法?,json,go,redis,revel,Json,Go,Redis,Revel,我正在使用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/pq

我正在使用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!!!
}

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

同时,如果您可以避免JSON并使用二进制格式,那么您不仅可以避免这个问题;您还将获得代码现在花费在将数字的ASCII十进制表示形式解析为二进制IEEE 754等价形式上的时间(并可能在解析过程中引入舍入错误)

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

做一个快速测试,生成一个包含2000个条目的映射,每个条目的一个片段包含1050个简单浮点数,这给了我20MB的JSON,在我的机器上解析需要1.16秒

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

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

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

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

如果发送方和解析器都未启动,或者如果您想进一步压缩性能而不是GOB,则应使用您自己定制的二进制格式,使用协议缓冲区或手动使用“encoding/binary”和friends。

试试看。它针对速度进行了优化,通常比标准的
编码/JSON
更快地解析JSON。另外,
fastjson
不需要遵循JSON模式的结构-单个解析器可以解析具有不同模式的多个JSON。

试试看


与官方版本相比,我的解码速度提高了2倍,更大的好处是jsoniter的API与encoding/json兼容。

这就是评测的情况。请阅读,至少,发布配置文件输出(如果您自己无法破解)。它可能会帮助其他人解决您的问题。这并不是说它会带来很大的不同,而是消除了不必要的转换:
pointTable,err:=redis.Bytes(c.Do(“GET”,“data”);Unmshal(pointTable和hashPoint)。另外,检查错误。与…相比,“非常慢”?我很惊讶他们都不够快。可以切换到protobufs,或者在
编码/binary
上构建一些东西,或者为此JSON编写解析器。我只是从表面上看你的文章,但如果你没有分析或计时,所以你知道解组速度很慢,我会验证这一点。如果需要5秒,它一定是一个相当大的结构——也许你想在Redis中存储一个散列,将单个字符串映射到
[]float64
s,那么你对每个请求都做一些工作?