[转载]Go JSON 技巧

相对于很多的语言来说, 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 . 那么对于这种情况我们怎么做合适呢 ?

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 进行性能的提升.

原文发布于微信公众号 - Golang语言社区(Golangweb)

原文发表时间:2018-02-23

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Seebug漏洞平台

披着狼皮的羊——寻找惠普多款打印机中的RCE漏洞

原文:https://foxglovesecurity.com/2017/11/20/a-sheep-in-wolfs-clothing-finding-rce...

11830
来自专栏FreeBuf

XSS的原理分析与解剖:第三章(技巧篇)

作者 Black-Hole 0×01 前言: 关于前两节url: 第一章:http://www.freebuf.com/articles/web/40520....

21070
来自专栏拂晓风起

cocos2d-js 调试办法 断点调试 Android真机调试

20720
来自专栏FreeBuf

一次入侵应急响应分析

本文是前段时间处理某用户被黑的分析总结,用户被黑的表现是使用爬虫访问用户网站的首页时会出现博彩关键字,而使用正常浏览器访问时无相关的博彩关键词。这是典型的黑帽S...

22920
来自专栏Thinks

你的第一个渐进式网站应用(5)

渐进式网站应用会很快启动并马上可用。在目前的状态中(step-04),我们的天气app启动很快,但是不可用。因为还木有数据。 我们要使用一个AJAX请求去获取数...

9030
来自专栏李蔚蓬的专栏

VMware Workstation14.1.3 & Ubuntu18.04从安装到实用的填坑之路

本机VMware Workstation环境是上学期安装的,拿的老师给的安装包,版本10.0.1。顺便装了个Ubuntu15.10。

16710
来自专栏腾讯Bugly的专栏

QUIC协议初探-iOS实践

| 导语 本文主要介绍了QUIC协议,以及初步研究的过程,用实践证明了QUIC协议在iOS平台的可行性 1、QUIC介绍 (1)QUIC(Quick UDP I...

1.3K60
来自专栏java架构师

关于GET和POST请求

网上看了一篇关于这两种请求的区别,感觉和之前看到的不太一样。 大众版: 1. GET使用URL或Cookie传参。而POST将数据放在BODY中。 2. GET...

34470
来自专栏FreeBuf

「无文件」攻击方式渗透实验

前几天看了一个文章《全球上百家银行和金融机构感染了一种“无文件”恶意程序,几乎无法检测》,觉得powershell很是神奇,自己希望亲手实验一下,以最大程度还原...

48880
来自专栏码洞

如何优雅的关闭Go Channel【译】

不要在消费端关闭channel,不要在有多个并行的生产者时对channel执行关闭操作。

28140

扫码关注云+社区

领取腾讯云代金券