Когда у вас есть io.Reader, наиболее распространенным способом чтения является ioutil.ReadAll, но это не лучший и самый эффективный способ.

Итак, вот три функции для сравнения различных методов демаршалинга JSON из io.Reader

  1. С ioutil.ReadAll
func IOUtilReadAll(reader io.Reader) (map[string]interface{}, error) {
   var (
      m    map[string]interface{}
      b, _ = ioutil.ReadAll(reader)
   )

   return m, json.Unmarshal(b, &m)
}

2. С io.Copy

func IOCopy(reader io.Reader) (map[string]interface{}, error) {
   var (
      m    map[string]interface{}
      buf  bytes.Buffer
      _, _ = io.Copy(&buf, reader)
   )

   return m, json.Unmarshal(buf.Bytes(), &m)
}

3. С json.Decoder

func JsonDecoder(reader io.Reader) (map[string]interface{}, error) {
   var m map[string]interface{}

   return m, json.NewDecoder(reader).Decode(&m)
}

А теперь давайте посмотрим на них!

var jsonStr = `{"one":"foobar","two":"foobar","three":"foobar","four":"foobar","five":"foobar","six":"foobar","seven":"foobar","eight":"foobar","nine":"foobar","ten":"foobar"}`
func BenchmarkJsonDecoder(b *testing.B) {
   b.ReportAllocs()
   for i := 0; i < b.N; i++ {
      JsonDecoder(strings.NewReader(jsonStr))
   }
}

func BenchmarkIOUtilReadAll(b *testing.B) {
   b.ReportAllocs()
   for i := 0; i < b.N; i++ {
      IOUtilReadAll(strings.NewReader(jsonStr))
   }
}

func BenchmarkIOCopy(b *testing.B) {
   b.ReportAllocs()
   for i := 0; i < b.N; i++ {
      IOCopy(strings.NewReader(jsonStr))
   }
}

Я передаю strings.NewReader всем трем функциям для согласованности, хотя для json.Decoder это не обязательно, так как это не истощает io.Reader.

И вот результаты ...

BenchmarkJsonDecoder
BenchmarkJsonDecoder-8        180230       6741 ns/op     2766 B/op       69 allocs/op
BenchmarkIOUtilReadAll
BenchmarkIOUtilReadAll-8      168019       6928 ns/op     4126 B/op       69 allocs/op
BenchmarkIOCopy
BenchmarkIOCopy-8             158901       6677 ns/op     2286 B/op       69 allocs/op

Бум! Хотя есть минимальные различия в ns / op, B / op - ошеломляющие 2x!

Но не верьте моим словам. Если вы используете ioutil.ReadAll, запустите тест и сравните разницу. Это может быть просто небольшое улучшение производительности вашего приложения, и эти усилия лучше потратить на что-то другое.

Надеюсь, это будет полезно. Хлопайте мне (точнее, этой статье), если вы так думаете.

Следуйте за мной, если вы еще этого не сделали!