缓慢的json编组和解编

时间:2016-07-21 08:45:05

标签: go

我的项目有一个要求API来返回一个数组(大约500个元素结构)

我尝试使用像fasthttpeasyjsonrapidjson这样的lib(使用cgo调用),但结果不够好。

你们有更好的推荐吗?

这是我的代码:

type Line struct {
    Time   string  `json:"time" bson:"time"`
    Open   float64 `json:"open" bson:"open"`
    Close  float64 `json:"close" bson:"close"`
    High   float64 `json:"high" bson:"high"`
    Low    float64 `json:"low" bson:"low"`
    Volume float64 `json:"volume" bson:"volume"`
    Amount float64 `json:"amount" bson:"amount"`
}

type MultiLines struct {
    AllLines []Line `json:"lines"`
}

测试代码:

func BenchmarkJson500(b *testing.B) {
    for i := 0; i < b.N; i++ {
        _, err := json.Marshal(&sliceData)
        if err != nil {
            panic(err)
        }
    }
}

func BenchmarkUnmarshalJson500(b *testing.B) {
    lines := make([]Line, 500)
    for i := 0; i < b.N; i++ {
        err := json.Unmarshal(sliceJson, &MultiLines{lines})
        if err != nil {
            panic(err)
        }
    }
}

func BenchmarkEasyJson500(b *testing.B) {
    for i := 0; i < b.N; i++ {
        _, err := sliceData.MarshalJSON()
        if err != nil {
            panic(err)
        }
    }
}

func BenchmarkEasyUnmarshalJson500(b *testing.B) {
    for i := 0; i < b.N; i++ {
        slice := MultiLines{}
        err := slice.UnmarshalJSON(sliceJson)
        if err != nil {
            panic(err)
        }
    }
}

基准测试结果:

BenchmarkUnmarshalJson500-4          500           2821450 ns/op
BenchmarkJson500-4                   500           2151984 ns/op

因为EasyJson重写了UnmarshalJSON / MarshalJSON,所以我在不同的时间使用生成的代码进行测试。

BenchmarkEasyJson500-4              1000           1434724 ns/op
BenchmarkEasyUnmarshalJson500-4     1000           1276298 ns/op

无论如何,ffjson与easyjson非常相似。

3 个答案:

答案 0 :(得分:0)

“结果不够好”是什么意思?

我使用标准库的json包:

https://golang.org/pkg/encoding/json/

据我所知,它在任何地方都使用,非常快速且资源友好。如果这也没有削减它,您可能需要考虑ffjson

https://github.com/pquerna/ffjson

请告诉我这是否有用!

答案 1 :(得分:0)

使用CASE时,您应该使用easyjson函数而不是easyjson.Unmarshal()。生成的自定义json.Unmarshal() / MarshalJSON()只是性能优化的一小部分(他们不使用UnmarshalJSON()包)。来自优化reflecteasyjson的{​​{1}}的主要利润。第一个没有进行JSON预验证,这非常慢。第二个使用并发来增强编码。

根据我的经验easyjson.Unmarshal(),对于具有简单结构的小型JSON或JSON(例如简单对象的数组),最多可以解组2次,对于大型或/和深层嵌套的JSON结构,最多可提升4次。不幸的是,我没有任何关于编组的统计数据。

答案 2 :(得分:0)

试试fastjson。它应该比encoding/json更快地解析输入字符串并且比easyjson更快。此外,它不需要为解析的JSON预定义Go结构,也不需要生成代码。请参阅以下示例:

var p fastjson.Parser
v, err := p.Parse(input)
if err != nil {
    log.Fatal(err)
}

for _, vv := range v.GetArray() {
    fmt.Printf("time=%s\n", vv.GetStringBytes("time"))
    fmt.Printf("open=%f\n", vv.GetFloat64("open"))
    // etc...
    // There is no need in extracting all the fields -
    // extract only required fields in order to get better performance.
}