[转载]Go JSON 技巧

Posted Golang语言社区

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[转载]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 进行性能的提升.


以上是关于[转载]Go JSON 技巧的主要内容,如果未能解决你的问题,请参考以下文章

Android课程---Android Studio使用小技巧:提取方法代码片段

小技巧

Go语言技巧之正确高效使用slice(听课笔记总结--简单易懂)

Go语言技巧之正确高效使用slice(听课笔记总结--简单易懂)

Go语言技巧之正确高效使用slice(听课笔记总结--简单易懂)

VS2015使用技巧 打开代码片段C#部分