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

时间:2015-03-26 15:16:47

标签: json go redis revel

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

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

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

我尝试过JsonLib,编码/ 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!!!
}

3 个答案:

答案 0 :(得分:8)

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

与此同时,如果您可以避免使用JSON并使用二进制格式,那么您不仅可以避免此问题;您还将获得代码现在花费时间将数字的ASCII十进制表示解析为其二进制IEEE 754等效值的时间(并且在执行此操作时可能会引入舍入错误。)

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

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

对于这些快速基准测试,我会充分利用三次运行,但我确保只测量实际的解析时间,在Unmarshal调用之前使用t0 := time.Now()并在其后打印time.Now().Sub(t0)

使用GOB,相同的地图会生成18 MB的数据,需要115 ms才能解析:
 十分之一的时间

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

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

如果发件人和解析器都不是Go,或者你想要比GOB更进一步挤出性能,你应该使用你自己的自定义二进制格式,使用Protocol Buffers或手动使用" encoding / binary& #34;和朋友们。

答案 1 :(得分:0)

试试fastjson。它针对速度进行了优化,与标准encoding/json相比,通常可以更快地解析JSON。此外,fastjson不需要遵循JSON模式的结构 - 单个解析器可以使用不同的模式解析多个JSON。

答案 2 :(得分:0)

尝试this fiddle

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