Lesson 21 — IO Streaming
Minh hoạ tương tác 3 module: Read loop, io.Copy buffer, io.Pipe.
Module 1 · Read loop với io.Reader
Reader có chuỗi nguồn dài 38 byte. Buffer của caller chỉ 8 byte. Quan sát mỗi lần Read(p) trả về n byte và xử lý EOF.
Source:
Buffer p:
đã đọc: 0
còn lại: 38
lần Read: 0
Module 2 · io.Copy buffer 32 KB so với load-all
Source 100 KB chảy qua buffer 32 KB sang destination. So sánh RAM dùng giữa streaming vs io.ReadAll.
SRC
100 / 100 KB còn lại
→
BUF (32 KB)
0 / 32 KB
→
DST
0 / 100 KB ghi
✓ io.Copy (streaming)
RAM peak: 0 KB
Chỉ giữ 1 buffer 32 KB bất kể source lớn cỡ nào.
✗ io.ReadAll (load all)
RAM peak: 0 KB
Bằng kích thước source. Source 4 GB → 4 GB RAM → OOM.
Module 3 · io.Pipe hand-off giữa 2 goroutine
Producer ghi vào pw; consumer đọc từ pr. Pipe đồng bộ (không buffer) → producer phải đợi consumer đọc xong mới ghi tiếp.
Goroutine A — Producer
State: idle
for i := 1..5 {
pw.Write("msg-i\n")
}
pw.Close()
io.Pipe
Goroutine B — Consumer
State: idle
sc := bufio.NewScanner(pr)
for sc.Scan() {
process(sc.Text())
}
Ghi chú
- Module 1: chú ý lần Read cuối thường trả
n > 0kèmio.EOF— cần xử lý cả 2. - Module 2: RAM của streaming = const 32 KB, không tỉ lệ với source. RAM của ReadAll = source size.
- Module 3: Pipe đồng bộ → khi consumer chậm, producer block ở
pw.Write. Đây là backpressure tự nhiên.