TGViewer
Библиотека Go (Golang) разработчика Библиотека Go (Golang) разработчика @golang_lib · 2.7K subscribers
Post #695 668
🌊 io.Reader и io.Writer: Лего для взрослых (и спасение от OOM)

Знакомый сценарий: микросервис скачивает отчет из внешней системы. Когда вы его писали, отчет весил 5 МБ. Через полгода бизнес вырос, отчет весит 5 ГБ. Ваш под в Kubernetes ловит OOM (Out Of Memory) и бесславно умирает.

Что делает в такой ситуации джуниор? Пытается увеличить лимиты памяти в Helm-чартах.
Почему так вышло? Потому что код выглядит вот так:

❌ Плохо (Смерть памяти):


resp, _ := http.Get(url)
// Вычитываем ВСЕ 5 Гигабайт в оперативную память
data, _ := io.ReadAll(resp.Body)
os.WriteFile("report.csv", data, 0644)



В Go есть два интерфейса, на которых держится вообще вся стандартная библиотека. Это io.Reader и io.Writer. В них всего по одному методу (Read и Write), но они превращают ваш код в систему сообщающихся сосудов.

Суть этих интерфейсов - стриминг (потоковая передача данных). Нам не нужно держать в памяти весь файл, чтобы переложить его из сети на диск или отправить другому сервису.

✅ Хорошо (Стриминг через io.Copy):


resp, _ := http.Get(url)
defer resp.Body.Close()

out, _ := os.Create("report.csv")
defer out.Close()

// Магия потока!
io.Copy(out, resp.Body)



Знаете, сколько оперативной памяти съест io.Copy при скачивании файла на 5 ГБ? Ровно 32 килобайта.
Под капотом функция создает маленький буфер, читает в него кусок данных из сети и тут же сбрасывает на диск. И так по кругу, пока поток не иссякнет.

🔥 Нюансы для Senior-ов: Композиция (Пайплайны)

Настоящая мощь io раскрывается, когда вы начинаете собирать эти интерфейсы в цепочки (паттерн Декоратор). Они вставляются друг в друга, как матрешки.

Представьте задачу: нужно скачать файл, на лету распаковать его из GZIP и посчитать SHA256-хэш, не сохраняя ничего на диск.


resp, _ := http.Get("http://example.com/data.gz")
defer resp.Body.Close()

// 1. Оборачиваем сетевой поток в GZIP-распаковщик (он тоже io.Reader!)
gzReader, _ := gzip.NewReader(resp.Body)
defer gzReader.Close()

// 2. Создаем "писателя", который считает хэш
hash := sha256.New()

// 3. io.TeeReader читает из gzReader и параллельно дублирует данные в hash
tee := io.TeeReader(gzReader, hash)

// 4. Сливаем данные в "никуда" (io.Discard),
// чтобы заставить насос качать данные по нашей трубе
io.Copy(io.Discard, tee)

fmt.Printf("Хэш файла: %x\n", hash.Sum(nil))



Мы только что обработали гигабайты сжатых данных за долю секунды, используя копейки RAM, ни разу не коснувшись жесткого диска.

Интерфейсы io - этоUnix-философия, зашитая прямо в язык. Освойте их, и вы перестанете бояться огромных объемов данных.

#golang #architecture #performance #io #bestpractices

📲 Мы в MAX

👉 @golang_lib
  • 👍 3
  • 🔥 2
More from @golang_lib
  1. Sep 22, 2026🔴AI кодинг интервью с разработчиком из международного FinTech в четверг в 19:00 ДА! Вайбк…
  2. Sep 21, 2026📢 sync.Cond: Как разбудить 10 000 горутин одним вызовом (и не сломать планировщик) Предст…
  3. Sep 17, 2026🔎 pprof: Как найти функцию, которая жрет 80% CPU Сервис на проде внезапно упирается в пол…
  4. Sep 7, 2026🗺️ sync.Map: Почему эта «серебряная пуля» иногда пробивает дно производительности Как тол…
  5. Sep 2, 2026☢️ Пакет unsafe: Взламываем систему типов Go Пакет unsafe - это легальный способ сказать к…
  6. Sep 1, 2026🔴 Тестовое собеседование с Go Senior с опытом работы в Яндексе, EPAM и Uzum в этот четвер…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →