Go 项目中高效处理 JSON

2021/08/30

Go 项目中高效处理 JSON

背景

标准库 encoding/json ,是兼容性最好的选择。但是在重度使用 json 的场景下,性能堪忧。我们应该区分具体使用场景,选择合适的 json 处理库。

加速 encoding

json-iterator/go

json-iterator/go 和标准库一样,也是基于反射实现的,但是它拥有更好的性能,其 API 兼容标准库,所以多数情况下可以直接替代 encoding/json 。

通过调整配置(jsoniter.ConfigFastest)还可以进一步优化性能。

type Config struct {
        IndentionStep                 int
        MarshalFloatWith6Digits       bool
        EscapeHTML                    bool
        SortMapKeys                   bool
        UseNumber                     bool
        DisallowUnknownFields         bool
        TagKey                        string
        OnlyTaggedField               bool
        ValidateJsonRawMessage        bool
        ObjectFieldMustBeSimpleString bool
        CaseSensitive                 bool
        MaxDepth                      int
}

segmentio/encoding

segmentio/encoding/json 也可以替代 encoding/json ,甚至比 json-iterator/go 拥有更高的性能。

但是兼容性方面有所妥协:

加速 decoding

mailru/easyjson

使用标准库的时候,我们会先定义结构体,给需要解析的字段加上 json tag 。

easyjson 作为命令行工具,通过自动代码生成的方式,可以避免用反射来解析 json ,从而提高 decoding 的性能。

easyjson -all <filename>.go

结合 go generate 在编译阶段生成 json 处理代码。

pquerna/ffjson 也是类似的原理。 但是 easyjson lexing and parsing

valyala/fastjson

解析任意 JSON 结构,而不需要代码生成。

可以非常快速的查询 json 中特定的字段

类似功能的还有 gjson ,但是 fastjson 的优势在于对于一段 json 只需要 parse 一次。

Benchmark

$ GOMAXPROCS=1 go test github.com/valyala/fastjson -bench='Parse$'
goos: linux
goarch: amd64
pkg: github.com/valyala/fastjson
BenchmarkParse/small/stdjson-map                   200000              7305 ns/op          26.01 MB/s             960 B/op              51 allocs/op
BenchmarkParse/small/stdjson-struct                500000              3431 ns/op          55.37 MB/s             224 B/op               4 allocs/op
BenchmarkParse/small/stdjson-empty-struct                   500000              2273 ns/op          83.58 MB/s             168 B/op               2 allocs/op
BenchmarkParse/small/fastjson                              5000000               347 ns/op         547.53 MB/s               0 B/op               0 allocs/op
BenchmarkParse/small/fastjson-get                          2000000               620 ns/op         306.39 MB/s               0 B/op               0 allocs/op
BenchmarkParse/medium/stdjson-map                            30000             40672 ns/op          57.26 MB/s           10196 B/op             208 allocs/op
BenchmarkParse/medium/stdjson-struct                         30000             47792 ns/op          48.73 MB/s            9174 B/op             258 allocs/op
BenchmarkParse/medium/stdjson-empty-struct                  100000             22096 ns/op         105.40 MB/s             280 B/op               5 allocs/op
BenchmarkParse/medium/fastjson                              500000              3025 ns/op         769.90 MB/s               0 B/op               0 allocs/op
BenchmarkParse/medium/fastjson-get                          500000              3211 ns/op         725.20 MB/s               0 B/op               0 allocs/op
BenchmarkParse/large/stdjson-map                              2000            614079 ns/op          45.79 MB/s          210734 B/op            2785 allocs/op
BenchmarkParse/large/stdjson-struct                           5000            298554 ns/op          94.18 MB/s           15616 B/op             353 allocs/op
BenchmarkParse/large/stdjson-empty-struct                     5000            268577 ns/op         104.69 MB/s             280 B/op               5 allocs/op
BenchmarkParse/large/fastjson                                50000             35210 ns/op         798.56 MB/s               5 B/op               0 allocs/op
BenchmarkParse/large/fastjson-get                            50000             35171 ns/op         799.46 MB/s               5 B/op               0 allocs/op
BenchmarkParse/canada/stdjson-map                               20          68147307 ns/op          33.03 MB/s        12260502 B/op          392539 allocs/op
BenchmarkParse/canada/stdjson-struct                            20          68044518 ns/op          33.08 MB/s        12260123 B/op          392534 allocs/op
BenchmarkParse/canada/stdjson-empty-struct                     100          17709250 ns/op         127.11 MB/s             280 B/op               5 allocs/op
BenchmarkParse/canada/fastjson                                 300           4182404 ns/op         538.22 MB/s          254902 B/op             381 allocs/op
BenchmarkParse/canada/fastjson-get                             300           4274744 ns/op         526.60 MB/s          254902 B/op             381 allocs/op
BenchmarkParse/citm/stdjson-map                                 50          27772612 ns/op          62.19 MB/s         5214163 B/op           95402 allocs/op
BenchmarkParse/citm/stdjson-struct                             100          14936191 ns/op         115.64 MB/s            1989 B/op              75 allocs/op
BenchmarkParse/citm/stdjson-empty-struct                       100          14946034 ns/op         115.56 MB/s             280 B/op               5 allocs/op
BenchmarkParse/citm/fastjson                                  1000           1879714 ns/op         918.87 MB/s           17628 B/op              30 allocs/op
BenchmarkParse/citm/fastjson-get                              1000           1881598 ns/op         917.94 MB/s           17628 B/op              30 allocs/op
BenchmarkParse/twitter/stdjson-map                             100          11289146 ns/op          55.94 MB/s         2187878 B/op           31266 allocs/op
BenchmarkParse/twitter/stdjson-struct                          300           5779442 ns/op         109.27 MB/s             408 B/op               6 allocs/op
BenchmarkParse/twitter/stdjson-empty-struct                    300           5738504 ns/op         110.05 MB/s             408 B/op               6 allocs/op
BenchmarkParse/twitter/fastjson                               2000            774042 ns/op         815.86 MB/s            2541 B/op               2 allocs/op
BenchmarkParse/twitter/fastjson-get                           2000            777833 ns/op         811.89 MB/s            2541 B/op               2 allocs/op

后续补上。

总结

更多