Hệ thống 22/09/2026 7 phút

Profiling CPU: tìm đúng hàm nóng (và đúng dòng) thay vì tối ưu theo cảm giác

Bạn đoán hàm A chậm, tối ưu cả ngày, hóa ra thủ phạm là hàm B. Profiler chấm dứt việc đoán mò: nó lấy mẫu stack định kỳ và chỉ ra hàm nào thực sự ngốn CPU bằng số. Bài này thử perf thật (bị container chặn — báo trung thực) rồi dùng Go pprof: hàm nóng chiếm 75.79% CPU, và pprof -list chỉ đúng dòng 17 ngốn 710ms. Bài cuối loạt Debug, kèm tổng kết 12 phần.

Lập trình 22/09/2026 6 phút

RE2 và Go regexp: cỗ máy đánh đổi tính năng để không bao giờ nổ

RE2 (Go, Rust, Google) chạy tuyến tính bằng cách mô phỏng mọi trạng thái cùng lúc thay vì thử-và-quay-lui. Bài này đo thật: cùng mẫu độc (a+)+b, RE2 xử lý 20 triệu ký tự trong 443ms với ns/ký tự hằng số ~22 — trong khi python treo ở 28 ký tự. Cái giá: RE2 từ chối lookahead, lookbehind và backreference, mỗi cái báo một lỗi khác nhau. Khi nào nên chọn nó.

Lập trình 22/09/2026 6 phút

Tối ưu regex: bốn mẹo đo được, và một mẹo biến 2 giây thành 0.33 micro-giây

Regex chậm hiếm khi vì máy yếu — thường vì mẫu viết chưa khéo. Bài này đo thật bốn kỹ thuật: biên dịch một lần (nhanh 1.84x), lớp phủ định thay lazy (chênh nhỏ nhưng an toàn hơn), atomic/possessive chặn backtracking (2222ms xuống 0.33µs), và neo để loại sớm (68ms xuống 0.21µs, nhanh hơn 329 nghìn lần). Kèm nguyên tắc quan trọng nhất: đo trước khi tối ưu.

Lập trình 22/09/2026 6 phút

Tối ưu JSON trong Go: cắt một nửa số lần cấp phát mà không đổi định dạng

Phần 1 đo được encoding/json tốn nhiều cấp phát, nhất là khi giải mã. Bài này giữ nguyên JSON nhưng tối ưu cách dùng: json.Encoder/Decoder ghi đọc thẳng io tránh []byte trung gian, và json.RawMessage hoãn giải mã phần chưa cần. Đo thật: Encoder cắt 50% số lần cấp phát khi ghi 1000 object, RawMessage giảm 61% cấp phát khi chỉ cần field ngoài, Decoder streaming giảm 32% bộ nhớ đổi lấy ~10% thời gian.

Lập trình 22/09/2026 6 phút

Zero-copy serialization: đọc một field trong 0,25 nano giây, không cấp phát

JSON và Protobuf phải giải mã cả bản ghi thành struct trước khi đọc một field — lãng phí khi bạn chỉ cần vài field trong message lớn. Zero-copy (FlatBuffers, Cap'n Proto) đọc thẳng field từ buffer bằng offset, không giải mã, không cấp phát. Bài này đo thật bằng Go: đọc một trường mất 0,25 ns và 0 lần cấp phát, so với 1524 ns và 9 lần khi phải unmarshal cả bản ghi — nhanh hơn khoảng 6000 lần.

Lập trình 22/09/2026 5 phút

Connection pool: vì sao pool mặc định 2 làm bạn mở 546 kết nối cho 2000 request

Keep-alive tái dùng một kết nối cho các request tuần tự, nhưng khi nhiều request chạy song song, mỗi luồng cần một kết nối cùng lúc — đó là việc của connection pool. Bài này chạy thật trong Go: 2000 request song song 50 luồng với pool mặc định (2) mở tới 546 kết nối vì churn, còn pool đủ lớn chỉ mở 50 và nhanh hơn. Giải thích cách chọn kích cỡ pool đúng.