比 encoding/json 更快地解析 json

2016-12-05 00:06:56 +08:00
 taowen

https://github.com/json-iterator/go

直接替换 json.Unmarshal

仍然使用反射实现,但是比 encoding/json 的版本更快。完整的测试代码: https://github.com/json-iterator/go-benchmark

func Benchmark_array_by_stardard_lib(b *testing.B) {
    b.ReportAllocs()
    for n := 0; n < b.N; n++ {
        sample := make([]int, 0, 10)
        json.Unmarshal([]byte(`[1,2,3,4,5,6,7,8,9]`), &sample)
    }
}

500000 2478 ns/op 408 B/op 14 allocs/op

func Benchmark_array_by_jsoniter(b *testing.B) {
    b.ReportAllocs()
    for n := 0; n < b.N; n++ {
        sample := make([]int, 0, 10)
        jsoniter.Unmarshal([]byte(`[1,2,3,4,5,6,7,8,9]`), &sample)
    }
}

2000000 740 ns/op 224 B/op 4 allocs/op

和 encoding/json 的区别是,标准库使用的是 reflect.ValueOf ,然后根据 json 的输入情况去找对应的 field 和 element 。而 jsoniter 的实现是反过来的,用 reflect.TypeOf 确定一个 json 的 schema ,然后根据 schema 产生对应的 decoder 。如果 json 输入不符合这个 decoder 则报错。

StAX 风格的 API

如果使用更底层的 api ,可以完全避免反射的开销

func Benchmark_array_by_jsoniter_direct(b *testing.B) {
	b.ReportAllocs()
	for n := 0; n < b.N; n++ {
		sample := make([]uint64, 0, 10)
		iter := jsoniter.ParseString(`[1,2,3,4,5,6,7,8,9]`)
		for iter.ReadArray() {
			sample = append(sample, iter.ReadUint64())
		}
	}
}

3000000 455 ns/op 112 B/op 2 allocs/op

2040 次点击
所在节点    Go 编程语言
9 条回复
spider82
2016-12-05 00:53:39 +08:00
mark
scnace
2016-12-05 01:15:13 +08:00
mark 一发起床看
myself659410
2016-12-05 09:44:33 +08:00
https://github.com/pquerna/ffjson 也是 encoding/json 的 2 倍到 3 倍
taowen
2016-12-05 10:05:17 +08:00
@myself659410 ffjson 需要 go generate 静态生成代码,而 jsoniter 的性能数字是在同样使用反射的前提下测得的。另外 ffjson 不支持用 io.Reader 做为输入,需要把所有的 json 读入为 []byte 再处理。
lwhile521
2016-12-05 10:16:04 +08:00
已给 star~
ggaaooppeenngg
2016-12-05 10:57:24 +08:00
用 reflect.TypeOf 确定一个 json 的 schema => 这个能认出 omitempty 这样的 tag 么?

112 B/op 内存分配貌似降下来了, 为什么避开反射时间增加了?
taowen
2016-12-05 11:34:27 +08:00
@ggaaooppeenngg 支持了 -, string 这些 tag ,没有支持 omitempty 。

```
type StructOfTag struct {
field1 string `json:"field-1"`
field2 string `json:"-"`
field3 int `json:",string"`
}

func Test_reflect_struct_tag_field(t *testing.T) {
err := jsoniter.Unmarshal(`{"field-1": "hello", "field2": "", "field3": "100"}`, &struct_)
if struct_.field1 != "hello" {
fmt.Println(err)
t.Fatal(struct_.field1)
}
if struct_.field2 != "world" {
fmt.Println(err)
t.Fatal(struct_.field2)
}
if struct_.field3 != 100 {
fmt.Println(err)
t.Fatal(struct_.field3)
}
}
```

不走反射速度是最快的啊 455 ns/op ,是标准库的 1/5
ggaaooppeenngg
2016-12-05 17:51:12 +08:00
@taowen 哦哦,看错了,赞!

在要求 json 完全相同的时候的确是不错的一个思路。
nomoon
2016-12-07 02:15:55 +08:00

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/325284

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX