分享
  1. 首页
  2. 文章

Go JSON 技巧

lingchao · · 1527 次点击 · · 开始浏览
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

相对于很多的语言来说, Go 的 JSON 解析可谓简单至极.

问题

通常情况下, 我们在 Go 中经常这样进行 JSON 的解码:

package main
import "encoding/json"
// jsonText comes from http://json.org/example.html
var jsonText = []byte(`
{
 "glossary":{
 "title":"example glossary",
 "GlossDiv":{
 "title":"S",
 "GlossList":{
 "GlossEntry":{
 "ID":"SGML",
 "SortAs":"SGML",
 "GlossTerm":"Standard Generalized Markup Language",
 "Acronym":"SGML",
 "Abbrev":"ISO 8879:1986",
 "GlossDef":{
 "para":"A meta-markup language, used to create markup languages such as DocBook.",
 "GlossSeeAlso":[
 "GML",
 "XML"
 ]
 },
 "GlossSee":"markup"
 }
 }
 }
 }
}`)
type glossary struct {
 Glossary struct {
 Title string `json:"title"`
 GlossDiv struct {
 Title string `json:"title"`
 GlossList struct {
 GlossEntry struct {
 ID string `json:"ID"`
 SortAs string `json:"SortAs"`
 GlossTerm string `json:"GlossTerm"`
 Acronym string `json:"Acronym"`
 Abbrev string `json:"Abbrev"`
 GlossDef struct {
 Para string `json:"para"`
 GlossSeeAlso []string `json:"GlossSeeAlso"`
 } `json:"GlossDef"`
 GlossSee string `json:"GlossSee"`
 } `json:"GlossEntry"`
 } `json:"GlossList"`
 } `json:"GlossDiv"`
 } `json:"glossary"`
}
func main() {
 var g glossary
 json.Unmarshal(jsonText, &g)
}

这样的解码对于我们日常使用好像也没什么问题, 起码能用 ? 对于一段 JSON, 我们解码的时候未必需要立即解码所有的部分, 什么意思呢 ?

拿上面的例子代码来说, 我们解码 jsonText , 可能仅需要马上使用 Title 和 GlossDiv.Title . 那么对于这种情况我们怎么做合适呢 ?

package main
import "encoding/json"
// jsonText comes from http://json.org/example.html
var jsonText = []byte(`
{
 ... // 此处省略, 同上
}`)
type glossarySectional struct {
 Glossary struct {
 Title string `json:"title"`
 GlossDiv struct {
 Title string `json:"title"`
 GlossList json.RawMessage `json:"GlossList"` // diff: delay JSON decoding
 } `json:"GlossDiv"`
 } `json:"glossary"`
}
func main() {
 var g glossarySectional
 json.Unmarshal(jsonText, &g)
}

没错, 魔法就在 GlossList json.RawMessage . 我们看相关文档怎么说:

RawMessage is a raw encoded JSON value. It implements Marshaler and Unmarshaler and can be used to delay JSON decoding or precompute a JSON encoding.

一目了然, RawMessage 起到了延迟解码一个 JSON 值的作用. 那么你可能会说, 这有啥用呢 ?

这对于普通的解码可能问题不大, 但是对于一些像消息传递(Kafka 这种), 细微的延迟可能会造成很大的影响. 我们可以通过简单的 benchmark 测试一下这细微的差别:

// 其他代码略 ... 完整代码参见: http://bit.ly/2skxY9L .
func benchmarkJSONUnmarshal(f func(), b *testing.B) {
 for n := 0; n < b.N; n++ {
 f()
 }
}
func BenchmarkJSONUnmarshal_0(b *testing.B) {
 benchmarkJSONUnmarshal(func() {
 var g glossary
 json.Unmarshal(jsonText, &g)
 }, b)
}
func BenchmarkJSONUnmarshal_1(b *testing.B) {
 benchmarkJSONUnmarshal(func() {
 var g glossarySectional
 json.Unmarshal(jsonText, &g)
 }, b)
}

我们通过运行 go test -run=NONE -bench=. ./... 可以得出(不同环境有略微差别):

BenchmarkJSONUnmarshal_0-8 200000 10565 ns/op
BenchmarkJSONUnmarshal_1-8 200000 7699 ns/op

差别幅度:

benchmark old ns/op new ns/op delta
BenchmarkJSONUnmarshal-8 10298 7591 -26.29%

可以看得出这个差别还是很大的, 特别是当 JSON 本身体量很大的时候.

结论

对于一些关乎性能的 JSON 解析的处理, 我们可以通过 json.RawMessage 进行性能的提升.


有疑问加站长微信联系(非本文作者)

本文来自:lingchao.xin

感谢作者:lingchao

查看原文:Go JSON 技巧

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

关注微信
1527 次点击
暂无回复
添加一条新回复 (您需要 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传

用户登录

没有账号?注册
(追記) (追記ここまで)

今日阅读排行

    加载中
(追記) (追記ここまで)

一周阅读排行

    加载中

关注我

  • 扫码关注领全套学习资料 关注微信公众号
  • 加入 QQ 群:
    • 192706294(已满)
    • 731990104(已满)
    • 798786647(已满)
    • 729884609(已满)
    • 977810755(已满)
    • 815126783(已满)
    • 812540095(已满)
    • 1006366459(已满)
    • 692541889

  • 关注微信公众号
  • 加入微信群:liuxiaoyan-s,备注入群
  • 也欢迎加入知识星球 Go粉丝们(免费)

给该专栏投稿 写篇新文章

每篇文章有总共有 5 次投稿机会

收入到我管理的专栏 新建专栏