json.Unmarshalとjson.NewDecoder.Decodeを使用したJSONのデコード


201

リクエストに応じてJSONペイロードをエンコードし、レスポンスからJSONボディをデコードする必要があるAPIクライアントを開発しています。

私はいくつかのライブラリからソースコードを読みましたが、私が見たものから、JSON文字列のエンコードとデコードには基本的に2つの可能性があります。

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)

私の場合、実装するHTTP応答を処理するとき io.Reader場合、2番目のバージョンは必要なコードが少ないようですが、両方を見たことがあるので、他のソリューションではなくソリューションを使用するかどうかに好みがあるかどうか疑問に思います。

さらに、この質問から受け入れられた答えは言う

json.Decoder代わりに使用してくださいjson.Unmarshal

理由は述べられていません。私は本当に使用を避けるべきjson.Unmarshalですか?


GitHubでのこのプルリクエストにより、Unmarshalへの呼び出しがjson.NewDecoderに置き換えられ、「JSONデコードでバッファが削除されました」。
Matt

それは、どの入力がより使いやすいかに依存します。blog.golang.org/json-and-goは、両方の手法の使用例を示しています。
rexposadas 2014年

15
IMO、ioutil.ReadAllあるほとんど常に行うには間違ったこと。それはあなたの目標とは関係ありませんが、最後の20TBの応答が}JSONの最後の応答の後であっても、パイプを下りてくる可能性があるものを格納するのに十分な連続メモリが必要です。
ダスティン

@Dustinこれio.LimitReaderを防ぐために使用できます。
Inanc Gumus

回答:


239

それは本当にあなたの入力が何であるかに依存します。のDecodeメソッドの実装を見ると、json.DecoderJSON値全体がメモリにバッファーされてから、Go値に非整列化されます。したがって、ほとんどの場合、これはメモリ効率が悪くなります(ただし、これは言語の将来のバージョンで簡単に変更される可能性があります)。

より良い経験則はこれです:

  • json.Decoderデータがio.Readerストリームからのものである場合、またはデータのストリームから複数の値をデコードする必要がある場合に使用します。
  • json.UnmarshalすでにメモリにJSONデータがある場合に使用します。

HTTPリクエストから読み取る場合はjson.Decoder、ストリームから読み取っているので、選択します。


25
また、Go 1.3ソースコードを検査することにより、json.Encoderを使用すると、エンコードのためにグローバルバッファープールが再利用され(新しいsync.Poolに基づく)、バッファーチャーンを大幅に減らすことができます。多くのjsonをエンコードしている場合。グローバルプールが1つしかないため、json.Encoderがそれを共有します。json.Marshalインターフェースでこれを実行できなかった理由は、バイトがユーザーに返され、ユーザーがバイトをプールに「返す」方法がないためです。したがって、多くのエンコードを実行している場合、json.Marshalは常にかなりの量のバッファチャーンを発生させます。
Aktau 2014年

@Flimzy:よろしいですか?ソースコードはまだデコード前に値全体をバッファーに読み込むと言っています:github.com/golang/go/blob/master/src/encoding/json/…。このBufferedメソッドは、値の後に内部バッファーに読み込まれた追加データを表示するためにあります。
James Henstridge 2017

@JamesHenstridge:いいえ、あなたはおそらく正しいです。私はあなたの発言をあなたが意図したものとは異なる方法で解釈しただけです。混乱をお詫びします。
Flimzy
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.