Одно понимание, которое я получил, когда узнал, как использовать Go, заключается в том, что ReadAll часто неэффективен для больших читателей и, как и в вашем случае, может привести к тому, что произвольный ввод будет очень большим и, возможно, утечкой памяти.Когда я начинал, я обычно выполнял синтаксический анализ JSON следующим образом:
data, err := ioutil.ReadAll(r)
if err != nil {
return err
}
json.Unmarshal(data, &v)
Затем я узнал о гораздо более эффективном способе синтаксического анализа JSON, который заключается в простом использовании типа Decoder
.
err := json.NewDecoder(r).Decode(&v)
if err != nil {
return err
}
Мало того, что это более кратко, это намного более эффективно, и с точки зрения памяти, и с точки зрения времени:
- Декодеру не нужно выделять огромный фрагмент байтачтобы приспособиться для чтения данных - он может просто повторно использовать крошечный буфер, который будет использоваться против метода
Read
, чтобы получить все данные и проанализировать их.Это экономит много времени при выделении ресурсов и снимает нагрузку с GC - . Декодер JSON может начать синтаксический анализ данных, как только поступит первая порция данных - ему не нужно ждать, пока все завершит загрузку.
Теперь, конечно, ваш вопрос не имеет ничего общего с JSON, но этот пример полезен для иллюстрации того, что если вы можете использовать Read
напрямую и анализировать порции данных одновременно, сделайте это.Особенно в случае HTTP-запросов синтаксический анализ выполняется быстрее, чем чтение / загрузка, поэтому это может привести к тому, что проанализированные данные будут почти сразу готовы к моменту окончания поступления тела запроса.
В вашем случае вы, по-видимому, на самом деле ничего не делаетеобработка данных на данный момент, поэтому не так много, чтобы предложить вам конкретно помочь.Но интерфейсы io.Reader
и io.Writer
являются эквивалентом каналов Go UNIX, поэтому их можно использовать в самых разных местах:
Запись данных в файл:
f, err := os.Create("file")
if err != nil {
return err
}
defer f.Close()
// Copy will put all the data from Body into f, without creating a huge buffer in memory
// (moves chunks at a time)
io.Copy(f, resp.Body)
Печать всего в стандартный вывод:
io.Copy(os.Stdout, resp.Body)
Передача тела ответа в тело запроса:
resp, err := http.NewRequest("POST", "https://example.com", resp.Body)