Golang Go语言中比 encoding/json 更快地解析 json

发布于 1周前 作者 zlyuanteng 来自 Go语言

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


Golang Go语言中比 encoding/json 更快地解析 json

更多关于Golang Go语言中比 encoding/json 更快地解析 json的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html

10 回复

mark

更多关于Golang Go语言中比 encoding/json 更快地解析 json的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


mark 一发起床看

https://github.com/pquerna/ffjson 也是 encoding/json 的 2 倍到 3 倍

ffjson 需要 go generate 静态生成代码,而 jsoniter 的性能数字是在同样使用反射的前提下测得的。另外 ffjson 不支持用 io.Reader 做为输入,需要把所有的 json 读入为 []byte 再处理。

用 reflect.TypeOf 确定一个 json 的 schema => 这个能认出 omitempty 这样的 tag 么?

112 B/op 内存分配貌似降下来了, 为什么避开反射时间增加了?

支持了 -, string 这些 tag ,没有支持 omitempty 。

<br>type StructOfTag struct {<br> field1 string `json:"field-1"`<br> field2 string `json:"-"`<br> field3 int `json:",string"`<br>}<br><br>func Test_reflect_struct_tag_field(t *testing.T) {<br> err := jsoniter.Unmarshal(`{"field-1": "hello", "field2": "", "field3": "100"}`, &amp;struct_)<br> if struct_.field1 != "hello" {<br> fmt.Println(err)<br> t.Fatal(struct_.field1)<br> }<br> if struct_.field2 != "world" {<br> fmt.Println(err)<br> t.Fatal(struct_.field2)<br> }<br> if struct_.field3 != 100 {<br> fmt.Println(err)<br> t.Fatal(struct_.field3)<br> }<br>}<br>

不走反射速度是最快的啊 455 ns/op ,是标准库的 1/5

哦哦,看错了,赞!

在要求 json 完全相同的时候的确是不错的一个思路。

在Golang中,虽然encoding/json是标准库提供的JSON解析工具,并且大多数情况下性能已经相当不错,但在某些特定场景下,开发者可能会寻求更快的JSON解析库来满足高性能需求。

一个值得推荐的替代库是jsoniterjsoniter是一个高性能的JSON解析/生成库,它基于encoding/json但进行了大量优化,包括更快的解码速度、更少的内存分配等。它支持Go的原生类型,并且API与encoding/json高度兼容,因此迁移成本较低。

此外,ffjson也是一个性能优异的JSON库。它使用代码生成技术,在编译时生成针对特定结构体优化的解析代码,从而在运行时实现更快的解析速度。但需要注意的是,ffjson的API与encoding/json不完全兼容,可能需要一些额外的适配工作。

然而,选择哪个库取决于你的具体需求,包括JSON数据的大小、结构复杂性以及你的应用对性能的敏感程度。在某些情况下,简单的优化encoding/json的使用方式(如减少内存分配、使用流式解析等)也可能带来显著的性能提升。

因此,在决定使用哪个库之前,建议对你的应用进行性能测试,比较不同库在你的特定场景下的表现。这样,你可以根据实际的性能数据和你的需求来做出最合适的选择。

回到顶部