json.Unmarshal과 json.NewDecoder.Decode를 사용하여 JSON 디코딩


203

요청시 JSON 페이로드를 인코딩하고 응답에서 JSON 본문을 디코딩 해야하는 API 클라이언트를 개발 중입니다.

여러 라이브러리에서 소스 코드를 읽었으며 본 내용에서 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)

필자의 경우을 구현하는 HTTP 응답을 처리 할 때 io.Reader두 번째 버전에는 더 적은 코드가 필요하지만 두 가지를 모두 보았으므로 다른 솔루션 대신 솔루션을 사용 해야하는지 선호하는 것이 있는지 궁금합니다.

또한 이 질문에 대한 대답

json.Decoder대신에 사용하십시오 json.Unmarshal.

그러나 그 이유는 언급되지 않았습니다. 정말로 사용하지 않아야 json.Unmarshal합니까?


GitHub 의이 풀 요청은 Unmarshal에 대한 호출을 json.NewDecoder로 대체하여 "JSON 디코딩에서 버퍼를 제거합니다."
Matt

사용하기 편리한 입력에 따라 다릅니다. blog.golang.org/json-and-go 는 두 기술을 모두 사용하는 예를 제공합니다.
rexposadas

15
IMO ioutil.ReadAll거의 항상 잘못된 일입니다. 목표와 관련이 없지만 마지막 20TB의 응답이 }JSON 의 마지막 이후 인 경우에도 파이프에서 내려 오는 모든 것을 저장할 수있는 충분한 연속 메모리가 필요합니다 .
더스틴

@Dustin io.LimitReader이를 방지하기 위해 사용할 수 있습니다 .
Inanc Gumus

답변:


240

실제로 입력 내용에 따라 다릅니다. 의 Decode메소드 구현을 살펴보면 json.DecoderGo 값으로 마샬링 해제하기 전에 전체 JSON 값을 메모리에 버퍼링합니다. 따라서 대부분의 경우 메모리 효율성이 향상되지 않습니다 (향후 버전의 언어에서는 쉽게 변경 될 수 있음).

따라서 더 나은 경험 법칙은 다음과 같습니다.

  • json.Decoder데이터가 io.Reader스트림에서 나오거나 데이터 스트림에서 여러 값을 디코딩해야하는 경우 사용하십시오 .
  • json.Unmarshal메모리에 이미 JSON 데이터가있는 경우 사용하십시오 .

HTTP 요청에서 읽는 경우 json.Decoder분명히 스트림에서 읽는 것이기 때문에 선택 합니다.


25
또한 : Go 1.3 소스 코드를 검사하여 인코딩을 위해 json.Encoder를 사용하면 전역 버퍼 풀 (새 sync.Pool 지원)을 재사용하여 버퍼 변동을 크게 줄일 수 있음을 알 수 있습니다 많은 JSON을 인코딩하는 경우. 하나의 글로벌 풀이 있으므로 다른 json.Encoder가 공유합니다. 이것이 json.Marshal 인터페이스에 대해 수행 할 수없는 이유는 바이트가 사용자에게 반환되고 사용자가 바이트를 풀로 "반환"하는 방법이 없기 때문입니다. 따라서 많은 인코딩을 수행하는 경우 json.Marshal에는 항상 약간의 버퍼 변동이 있습니다.
Aktau

@Flimzy : 확실합니까? 소스 코드는 github.com/golang/go/blob/master/src/encoding/json/… 디코딩하기 전에 버퍼에 전체 값을 읽습니다 . 이 Buffered방법을 사용하면 값 다음에 내부 버퍼로 읽힌 추가 데이터를 볼 수 있습니다.
James Henstridge

@JamesHenstridge : 아니요, 아마 옳습니다. 나는 당신이 의도 한 것과 다르게 당신의 진술을 해석하고있었습니다. 혼란에 대한 사과.
Flimzy
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.