前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >easyjson 源码调试学习

easyjson 源码调试学习

作者头像
golangLeetcode
发布2022-08-02 18:57:32
4320
发布2022-08-02 18:57:32
举报
文章被收录于专栏:golang算法架构leetcode技术php

json解析逻辑一直很繁琐,是go项目可能遇到的性能瓶颈之一。easyjson的解决思路很直观,代码量也不大,整体思路是根据源码中的结构体生成定制化的marshal和unmarshal方法,由于是定制化的,解析的时候没有反射,性能可以做到很好,下面通过调试学习了一下定制化的marshal和unmarshal方法是如何生成的。

我们可以在Edit Configuration中进行配置 然后我们在这个窗口去配置当前Go程序的参数 配置好之后点击Debug即可。

我们从main函数入口开始找到了如下关键路径,首先是输入文件的解析

代码语言:javascript
复制
err := p.Parse(fname, fInfo.IsDir());

会解析我们输入的文件example.go

代码语言:javascript
复制
 package example 
 type AutoGenerated struct { 
 Name string json:"name" 
 Value int json:"value" 
 }

解析过程中会调用

代码语言:javascript
复制
f, err := parser.ParseFile(fset, fname, nil, parser.ParseComments)

获取ast

然后获取语法树中我们感兴趣的部分

代码语言:javascript
复制
 ast.Walk(&visitor{Parser: p}, f)

重点是

代码语言:javascript
复制
func (v *visitor) Visit(n ast.Node) (w ast.Visitor) {
 switch n := n.(type) { 
 case *ast.Package: 
 return v 
 case *ast.File: 
 v.PkgName = n.Name.String() 
 return v 
 case *ast.GenDecl:
  v.explicit = v.needType(n.Doc.Text()) 
  if !v.explicit && !v.AllStructs { 
  return nil
   } 
   return v
    case *ast.TypeSpec: 
    v.name = n.Name.String() // Allow to specify non-structs explicitly independent of '-all' flag. 
    if v.explicit { 
    v.StructNames = append(v.StructNames, v.name) 
    return nil 
    } 
    return v 
    case *ast.StructType: 
    v.StructNames = append(v.StructNames, v.name) 
    return nil 
    } 
    return nil 
    }

解析我们感兴趣的包,结构体声明等信息

代码语言:javascript
复制
g.writeStub();

生成文件 /Users/didi/goLang/src/github.com/xiazemin/go-json/json2go/example_easyjson.go

代码语言:javascript
复制
// TEMPORARY AUTOGENERATED FILE: easyjson stub code to make the package 
// compilable during generation. 
package example 
import ( 
“github.com/mailru/easyjson/jwriter” 
“github.com/mailru/easyjson/jlexer” 
) 
func ( AutoGenerated ) MarshalJSON() ([]byte, error) { 
return nil, nil 
} 
func (* AutoGenerated ) UnmarshalJSON([]byte) error {
 return nil 
 } 
 func ( AutoGenerated ) MarshalEasyJSON(w jwriter.Writer) {
 } 
 func ( AutoGenerated ) UnmarshalEasyJSON(l *jlexer.Lexer) {
 } 
 type EasyJSON_exporter_AutoGenerated *AutoGenerated g.writeMain()

生成临时文件 /Users/didi/goLang/src/github.com/xiazemin/go-json/json2go/easyjson-bootstrap501241316.go

代码语言:javascript
复制
// +build ignore 
// TEMPORARY AUTOGENERATED FILE: easyjson bootstapping code to launch 
// the actual generator. 
package main 
import ( 
“fmt” 
“os” 
“github.com/mailru/easyjson/gen” 
pkg “github.com/xiazemin/go-json/json2go” 
) 
func main() { 
g := gen.NewGenerator(“example_easyjson.go”) 
g.SetPkg(“example”, “github.com/xiazemin/go-json/json2go”) 
g.Add(pkg.EasyJSON_exporter_AutoGenerated(nil)) 
if err := g.Run(os.Stdout); 
err != nil { 
fmt.Fprintln(os.Stderr, err) 
os.Exit(1) 
}
} 

创建另一个临时文件 /Users/didi/goLang/src/github.com/xiazemin/go-json/json2go/example_easyjson.go.tmp

执行命令

代码语言:javascript
复制
go run -tags “” easyjson-bootstrap501241316.go 

将std out 指定为example_easyjson.go.tmp 内容为

代码语言:javascript
复制
// Code generated by easyjson for marshaling/unmarshaling. DO NOT EDIT.

package example

import (
  json "encoding/json"
  easyjson "github.com/mailru/easyjson"
  jlexer "github.com/mailru/easyjson/jlexer"
  jwriter "github.com/mailru/easyjson/jwriter"
)

// suppress unused package warning
var (
  _ *json.RawMessage
  _ *jlexer.Lexer
  _ *jwriter.Writer
  _ easyjson.Marshaler
)

func easyjsonEeca4a30DecodeGithubComXiazeminGoJsonJson2go(in *jlexer.Lexer, out *AutoGenerated) {
  isTopLevel := in.IsStart()
  if in.IsNull() {
    if isTopLevel {
      in.Consumed()
    }
    in.Skip()
    return
  }
  in.Delim('{')
  for !in.IsDelim('}') {
    key := in.UnsafeString()
    in.WantColon()
    if in.IsNull() {
      in.Skip()
      in.WantComma()
      continue
    }
    switch key {
    case "name":
      out.Name = string(in.String())
    case "value":
      out.Value = int(in.Int())
    default:
      in.SkipRecursive()
    }
    in.WantComma()
  }
  in.Delim('}')
  if isTopLevel {
    in.Consumed()
  }
}
func easyjsonEeca4a30EncodeGithubComXiazeminGoJsonJson2go(out *jwriter.Writer, in AutoGenerated) {
  out.RawByte('{')
  first := true
  _ = first
  {
    const prefix string = ",\"name\":"
    out.RawString(prefix[1:])
    out.String(string(in.Name))
  }
  {
    const prefix string = ",\"value\":"
    out.RawString(prefix)
    out.Int(int(in.Value))
  }
  out.RawByte('}')
}

// MarshalJSON supports json.Marshaler interface
func (v AutoGenerated) MarshalJSON() ([]byte, error) {
  w := jwriter.Writer{}
  easyjsonEeca4a30EncodeGithubComXiazeminGoJsonJson2go(&w, v)
  return w.Buffer.BuildBytes(), w.Error
}

// MarshalEasyJSON supports easyjson.Marshaler interface
func (v AutoGenerated) MarshalEasyJSON(w *jwriter.Writer) {
  easyjsonEeca4a30EncodeGithubComXiazeminGoJsonJson2go(w, v)
}

// UnmarshalJSON supports json.Unmarshaler interface
func (v *AutoGenerated) UnmarshalJSON(data []byte) error {
  r := jlexer.Lexer{Data: data}
  easyjsonEeca4a30DecodeGithubComXiazeminGoJsonJson2go(&r, v)
  return r.Error()
}

// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
func (v *AutoGenerated) UnmarshalEasyJSON(l *jlexer.Lexer) {
  easyjsonEeca4a30DecodeGithubComXiazeminGoJsonJson2go(l, v)
}

重命名,流程结束

关键代码如下:

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-07-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 golang算法架构leetcode技术php 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档