深入 Go 中各个高性能 JSON 解析库

本文深入探讨了Go中几个高性能的JSON解析库,包括标准库JSON Unmarshal、fastjson、GJSON和jsonparser。通过对源码的分析,揭示了它们在性能和功能上的特点。标准库虽然功能全面但性能较低,而fastjson和GJSON提供了更快的速度,其中fastjson更注重速度,GJSON则提供了一些额外的功能,如模糊匹配。jsonparser则在保持高性能的同时,提供了自定义回调函数的能力。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

深入 Go 中各个高性能 JSON 解析库

转载请声明出处哦~,本篇文章发布于luozhiyun的博客:https://www.luozhiyun.com/archives/535

其实本来我是没打算去看 JSON 库的性能问题的,但是最近我对我的项目做了一次 pprof,从下面的火焰图中可以发现在业务逻辑处理中,有一半多的性能消耗都是在 JSON 解析过程中,所以就有了这篇文章。

image-20210519160937326

这篇文章深入源码分析一下在 Go 中标准库是如何解析 JSON 的,然后再看看有哪些比较流行的 Json 解析库,以及这些库都有什么特点,在什么场景下能更好的帮助我们进行开发。

主要介绍分析以下几个库:

库名 Star
标准库 JSON Unmarshal
valyala/fastjson 1.2 k
tidwall/gjson 8.3 k
buger/jsonparser 4 k

json-iterator 库也是一个非常有名的库,但是我测了一下性能和标准库相差很小,相比之下还是标准库更值得使用;

Jeffail/gabs 库与 bitly/go-simplejson 直接用的标准库的 Unmarshal 来进行解析,所以性能上和标准库一致,本篇文章也不会提及;

easyjson这个库需要像 protobuf 一样为每一个结构体生成序列化的代码,具有强入侵性,我个人不是很喜欢,所以也没提及。

上面的这些库是我能搜到的 Star 数大于 1k 比较知名,并且仍然在迭代的 JSON 解析库,如果有遗漏的,可以联系我,我会补上。

标准库 JSON Unmarshal

分析

func Unmarshal(data []byte, v interface{
   
   })

官方的 JSON 解析库需要传两个参数,一个是需要被序列化的对象,另一个是表示这个对象的类型。

在真正执行 JSON 解析之前会调用 reflect.ValueOf来获取参数 v 的反射对象。然后会获取到传入的 data 对象的开头非空字符来界定该用哪种方式来进行解析。

func (d *decodeState) value(v reflect.Value) error {
   
   
	switch d.opcode {
   
   
	default:
		panic(phasePanicMsg)
	// 数组 
	case scanBeginArray:
		...
	// 结构体或map
	case scanBeginObject:
		...
	// 字面量,包括 int、string、float 等
	case scanBeginLiteral:
		...
	}
	return nil
}

如果被解析的对象是以[开头,那么表示这是个数组对象会进入到 scanBeginArray 分支;如果是以{ 开头,表明被解析的对象是一个结构体或 map,那么进入到 scanBeginObject 分支 等等。

以解析对象为例:

func (d *decodeState) object(v reflect.Value) error {
   
   
	...  
	var fields structFields
	// 检验这个对象的类型是 map 还是 结构体
	switch v.Kind() {
   
   
	case reflect.Map: 
		...
	case reflect.Struct:
		// 缓存结构体的字段到 fields 对象中
		fields = cachedTypeFields(t)
		// ok
	default:
		d.saveError(&UnmarshalTypeError{
   
   Value: "object", Type: t, Offset: int64(d.off)})
		d.skip()
		return nil
	}

	var mapElem reflect.Value
	origErrorContext := d.errorContext
	// 循环一个个解析JSON字符串中的 key value 值
	for {
   
     
		start := d.readIndex()
		d.rescanLiteral()
		item := d.data[start:d.readIndex()]
		// 获取 key 值
		key, ok := unquoteBytes(item)
		if !ok {
   
   
			panic(phasePanicMsg)
		} 
		var subv reflect.Value
		destring := false   
		... 
		// 根据 value 的类型反射设置 value 值 
		if destring {
   
   
			// value 值是字面量会进入到这里
			switch qv := d.valueQuoted().(type) {
   
   
			case nil:
				if err := d.literalStore(nullLiteral, subv, false); err != nil {
   
   
					return err
				}
			case string:
				if err := d.literalStore([]byte(qv), subv, true); err != nil {
   
   
					return err
				}
			default:
				d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal unquoted value into %v", subv.Type()))
			}
		} else {
   
   
			// 数组或对象会递归调用 value 方法
			if err := d.value(subv); err != 
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值