我的项目有一个要求API来返回一个数组(大约500个元素结构)
我尝试使用像fasthttp
,easyjson
,rapidjson
这样的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非常相似。
答案 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()
包)。来自优化reflect
和easyjson
的{{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.
}