Go Concurrency Distilled: Cẩm nang cô đọng về lập trình đồng thời trong Go
Một cuốn sách nhỏ tổng hợp các chủ đề quan trọng nhất về lập trình đồng thời (concurrency) trong Go, từ goroutine, channel, select đến mutex, atomic và các công cụ chẩn đoán hiệu năng. Đây là tài liệu ôn tập nhanh dành cho lập trình viên Go đã có kinh nghiệm, với ví dụ tương tác trực tuyến và không sử dụng AI để tạo nội dung.

Go Concurrency Distilled: Cẩm nang cô đọng về lập trình đồng thời trong Go
Lập trình đồng thời (concurrency) là một trong những điểm mạnh cốt lõi của Go, nhưng cũng là chủ đề khiến không ít lập trình viên bối rối. Cuốn sách nhỏ "Go Concurrency Distilled" của tác giả Anton Zhiyanov ra đời nhằm giải quyết đúng vấn đề đó: cung cấp một bản tóm tắt ngắn gọn, súc tích về toàn bộ các công cụ đồng thời mà Go cung cấp.
Điểm đáng chú ý là cuốn sách đi kèm ví dụ tương tác — bạn có thể sửa code và nhấn Run ngay trên trình duyệt. Ngoài ra còn có phiên bản PDF với ví dụ tĩnh. Tác giả nhấn mạnh đây là tài liệu ôn tập nhanh, không phải hướng dẫn cho người mới bắt đầu, và toàn bộ nội dung không sử dụng AI để tạo.
Goroutine — Nền tảng của mọi thứ
Nền tảng của lập trình đồng thời trong Go chính là goroutine — các hàm được khởi chạy bằng từ khóa go:
func main() {
var wg sync.WaitGroup
wg.Add(2)
go func() {
defer wg.Done()
fmt.Println("worker 1")
}()
go func() {
defer wg.Done()
fmt.Println("worker 2")
}()
wg.Wait()
}
Runtime của Go sẽ điều phối các goroutine này và phân phối chúng lên các luồng (thread) của hệ điều hành chạy trên các nhân CPU. So với thread hệ điều hành, goroutine nhẹ hơn rất nhiều, cho phép bạn tạo hàng trăm hay thậm chí hàng nghìn goroutine mà không tốn kém tài nguyên.
Các goroutine hoàn toàn độc lập với nhau. Hàm main cũng là một goroutine nhưng được khởi chạy ngầm khi chương trình bắt đầu. Khi main kết thúc, mọi goroutine khác cũng dừng theo.
Để chờ các goroutine hoàn thành, ta dùng wait group (sync.WaitGroup). Bộ đếm bên trong sẽ tăng lên khi gọi Add(n) và giảm đi khi gọi Done(). Hàm Wait() sẽ chặn goroutine gọi nó cho đến khi bộ đếm về 0.
Go cũng cung cấp WaitGroup.Go — tự động tăng bộ đếm, chạy hàm trong một goroutine và giảm bộ đếm khi xong, giúp code gọn gàng hơn nhiều.
Channel — Cầu nối giữa các goroutine
Các goroutine có thể truyền giá trị cho nhau thông qua channel. Hãy hình dung channel như một cửa sổ mà một goroutine ném thứ gì đó vào và goroutine khác bắt lấy:
func main() {
messages := make(chan string)
go func() { messages <- "ping" }()
msg := <-messages
fmt.Println(msg)
}
Channel là công cụ giao tiếp linh hoạt bậc nhất trong Go, và triết lý nổi tiếng của Go là:
"Đừng giao tiếp bằng cách chia sẻ bộ nhớ; hãy chia sẻ bộ nhớ bằng cách giao tiếp."
Select, Pipeline và xử lý thời gian
Select cho phép một goroutine chờ đồng thời trên nhiều thao tác channel, tương tự như switch nhưng dành cho channel.
Pipeline là chuỗi các thao tác mà mỗi bước nhận dữ liệu đầu vào, xử lý theo cách riêng rồi xuất ra đầu ra. Đầu vào và đầu ra của mỗi thao tác đều là channel. Một pipeline điển hình gồm:
- Reader: Đọc dữ liệu từ file, database hoặc mạng.
- N bộ xử lý: Biến đổi, lọc, tổng hợp hoặc làm giàu dữ liệu.
- Writer: Ghi dữ liệu đã xử lý ra file, database hoặc mạng.
Về xử lý thời gian, Go cung cấp Timer (time.Timer) — cấu trúc có channel C sẽ gửi thời gian hiện tại khi hết hạn, hữu ích cho việc lên kế hoạch thực thi trong tương lai. Ticker thì lặp lại theo chu kỳ đều đặn.
Context đóng vai trò then chốt trong việc hủy thao tác, mang theo deadline, timeout và tín hiệu hủy xuyên suốt các tầng gọi hàm.
Data race và Race condition — Hai khái niệm dễ nhầm lẫn
Đây là phần quan trọng nhất mà bất kỳ lập trình viên Go nào cũng phải nắm vững:
- Data race là tình huống hai goroutine truy cập cùng một vùng nhớ mà ít nhất một trong số đó là ghi, không có đồng bộ.
- Race condition là lỗi logic khi kết quả phụ thuộc vào thứ tự thực thi không xác định.
Mutex (sync.Mutex) là công cụ quen thuộc để bảo vệ vùng găng (critical section). Ngoài ra còn có semaphore để giới hạn số lượng goroutine truy cập tài nguyên, và condition variable để phát tín hiệu giữa các goroutine.
Go cũng cung cấp sync.Once cho việc khởi tạo an toàn đúng một lần, và object pool (sync.Pool) giúp giảm tải cho garbage collector.
Atomic — Khi nào dùng, khi nào không
Gói sync/atomic cung cấp các thao tác nguyên tử. Điểm mấu chốt cần nhớ:
Tổ hợp các thao tác atomic luôn KHÔNG mang tính nguyên tử.
Ví dụ, đoạn code sau gây race condition dù dùng atomic:
func increment() {
delta.Add(1)
sleep(10)
counter.Add(delta.Load()) // Không nguyên tử!
}
Cách chống lỗi triệt để là dùng mutex để bao trọn thao tác phức hợp. Tuy nhiên, đôi khi atomic có thể thay thế mutex để thoát sớm, ví dụ trong mẫu thiết kế "Gate" dùng CompareAndSwap để bỏ qua các lần gọi lặp.
Testing và chẩn đoán hiệu năng
Nếu chương trình đồng thời dùng channel hoặc kiểu tùy chỉnh với phương thức đồng bộ như Wait, bạn có thể dùng chúng trong test — giúp test không phức tạp hơn nhiều so với code đồng bộ.
Về profiling, Go cung cấp bộ công cụ mạnh mẽ:
- CPU profile: Thu thập qua
pprof.StartCPUProfilehoặc endpointnet/http/pprof, xem bằnggo tool pprof -http=localhost:8080. - Tracing: Ghi lại các sự kiện liên quan đến đồng thời và bộ nhớ, thu qua endpoint
/debug/pprof/trace, xem bằnggo tool trace. - Flight recording: Ghi trace tự động với cửa sổ trượt giới hạn theo kích thước hoặc thời lượng, giúp luôn có sẵn trace gần nhất khi sự cố xảy ra.
Kết luận
Cuốn sách tổng kết lại bộ công cụ Go dành cho lập trình đồng thời:
- Goroutine để chạy tác vụ đồng thời.
- Channel và select làm công cụ giao tiếp linh hoạt.
- Timer và ticker để xử lý thời gian.
- Context để hủy thao tác.
- Wait group để đồng bộ goroutine.
- Mutex để ngăn race condition.
- Condition variable để phát tín hiệu sự kiện.
- Once cho khởi tạo một lần an toàn.
- Pool để giảm tải garbage collector.
- Atomic operations cho các thao tác đơn giản.
Đối với lập trình viên Go tại Việt Nam — đặc biệt những ai đang làm backend, microservices hay hệ thống xử lý dữ liệu lớn — đây là tài liệu ôn tập cực kỳ hữu ích. Go đang ngày càng phổ biến trong cộng đồng công nghệ Việt Nam nhờ hiệu năng cao và khả năng đồng thời mạnh mẽ, nên việc nắm chắc các khái niệm này là lợi thế cạnh tranh rõ rệt.
Bài viết liên quan

Công nghệ
Mô hình AI hàng đầu giỏi Vật lý đến đâu? Nghiên cứu mới chỉ ra các bài kiểm tra hiện hành đang đánh giá sai
16 tháng 9, 2026

Công nghệ
Nộp đơn xin việc lẽ ra nên khó hơn. Thật đấy
25 tháng 8, 2026
Công nghệ
"Token-space font": Công cụ tạo font chữ nơi mỗi token LLM có cùng độ rộng
26 tháng 9, 2026