2014-01-17 53 views
105

我正在开发的API的客户端,其中我需要以编码上请求一个JSON有效载荷和从响应解码JSON体。解码JSON在Golang VS json.NewDecoder.Decode

我从几个图书馆阅读源代码,从我所看到的,我有编码和JSON字符串解码基本上有两种可能性。

使用json.Unmarshal通过整个响应字符串

data, err := ioutil.ReadAll(resp.Body) 
if err == nil && data != nil { 
    err = json.Unmarshal(data, value) 
} 

或使用json.NewDecoder.Decode

err = json.NewDecoder(resp.Body).Decode(value) 

在我的情况下,实现io.Reader,第二个版本似乎需要更少的代码HTTP响应处理时,但是既然我看到了两者,我想知道我是否应该使用解决方案而不是其他解决方案。

此外,the accepted answer from this question

请使用json.Decoder代替json.Unmarshal

,但它没有提到的原因。我真的应该避免使用json.Unmarshal

+0

这[GitHub上拉入请求(https://github.com/codegangsta/martini-contrib/pull/84)代替调用解组与json.NewDecoder“在JSON解码中删除缓冲区”。 – Matt

+0

它只是取决于什么输入更方便您使用。 http://blog.golang.org/json-and-go给出了使用这两种技术的例子。 – rexposadas

+12

IMO,'ioutil.ReadAll'几乎总是做错事。这与您的目标无关,但要求您有足够的连续内存来存储管道中可能存在的任何内容,即使最后20TB的响应位于JSON中最后一个'}之后。 – Dustin

回答

134

这真的取决于你输入的是什么。如果你看看json.DecoderDecode方法的实现,它解组成围棋值之前缓存在内存中的整个JSON值。所以在大多数情况下,它不会有更高的内存效率(尽管在未来的语言版本中这很容易改变)。

所以拇指更好的规则是这样的:

  • 使用json.Decoder如果你的数据是从io.Reader陆续建成,或者需要多个值,从数据流进行解码。
  • 使用json.Unmarshal如果你已经在内存中的JSON数据。

对于从HTTP请求中读取的情况,我会选择json.Decoder,因为您显然正在从流中读取数据。

+20

另外:通过检查Go 1.3源代码,我们还可以得知,对于编码,如果使用json.Encoder,它将重用全局缓冲池(由新的sync.Pool支持),这应该减少缓冲区转换a很多,如果你编码了很多json。只有一个全局池非常不同,json.Encoder分享它。无法为json.Marshal接口完成这个原因是因为字节返回给用户,用户没有办法将字节“返回”到池中。所以如果你做了很多编码,json.Marshal总是有很多缓冲区流失。 – Aktau

+0

@Flimzy:你确定?源代码仍然表示它在解码之前将整个值读入缓冲区:https://github.com/golang/go/blob/master/src/encoding/json/stream.go#L56-L62。 'Buffered'方法可以让你看到任何额外的数据,在数值后被读入内部缓冲区。 –

+0

@JamesHenstridge:不,你可能是对的。我只是以不同于你的意图来解释你的陈述。抱歉的混淆。 – Flimzy

-4

我们必须在解码前从管道获取[]字节,因此在处理HTTP连接时需要从io读取数据,所以我认为这两个函数是相同的。但是当数据保存在内存中,或者我们已经得到[]字节时,我们可以直接使用Unmarshal,这样会更好。在读写HTTP连接,WebSockets或文件时使用json.Decoder

json.Unmarshal用于当输入为[]字节