Go Scheduler — Under The Hood 🧠⚙️
Các bạn đã biết qua về Golang, đặc biệt là goroutine – "vũ khí tối thượng" của Go giúp viết các chương trình concurrent một cách dễ dàng và hiệu quả.
Trong bài viết này, mình không đi sâu vào ưu nhược điểm của goroutine, mà sẽ cùng tìm hiểu cách Go runtime quản lý các goroutines, cụ thể như:
- Goroutine nào sẽ được thực thi trước?
- Làm thế nào để scale lên/xuống?
- Điều gì xảy ra khi một goroutine bị block?
1. Kiến trúc GPM (Goroutine, Processor, Machine)
Thành phần | Vai trò |
---|---|
G (Goroutine) |
Đại diện cho một goroutine – chứa thông tin về ngăn xếp, trạng thái, và đoạn mã sẽ thực thi. |
M (Machine) |
Là luồng hệ điều hành (OS thread) – thực thi goroutine thông qua P . |
P (Processor) |
Bộ xử lý logic – quản lý local run queue và điều phối thực thi goroutine. |
2. Sched
là gì?
Sched
là một struct toàn cục trong Go runtime, chịu trách nhiệm điều phối việc chạy của goroutine:
- Quản lý Global Run Queue (hàng đợi toàn cục)
- Danh sách các
M
đang hoạt động hoặc đang đợi - Danh sách các
P
đã cấp phát hoặc đang rảnh - Global locks, counters, thống kê...
Sched
giống như một trung tâm điều phối giao thông, đảm bảo mọi thứ diễn ra trơn tru và công bằng giữa các goroutine.
3. Trạng thái của một Goroutine
🟡 Runnable
Goroutine ở trạng thái này khi:
- Được tạo bằng từ khóa
go
- Hoặc được đánh thức từ trạng thái
Blocked
(ví dụ sau khi đợi I/O hoặc mutex)
🔹 Lúc này, goroutine sẵn sàng được lên lịch, nhưng chưa thực sự chạy.
🟢 Running
Goroutine đang:
- Thực thi mã trên OS thread thông qua
P
- Tiến hành xử lý logic của chương trình
🔴 Blocked
Goroutine rơi vào trạng thái này khi:
- Chờ dữ liệu từ channel
- Chờ lock (mutex)
- Chờ thao tác I/O hoặc mạng hoàn thành
✅ Khi unblock, goroutine chuyển về lại trạng thái
Runnable
4. M:N Scheduler — Cơ chế ghép goroutine và thread
Go sử dụng mô hình M:N scheduler:
- N goroutines được ánh xạ lên M luồng hệ điều hành (
M
) - Mỗi
M
thực thi quaP
⚙️ Khi chương trình bắt đầu:
- Go runtime tạo ra số lượng thread (
M
) dựa trên phần cứng:
số lõi CPU × số luồng phần cứng trên mỗi lõi
.
Ví dụ: CPU 8 lõi, mỗi lõi 2 thread ⇒ 8 × 2 = 16
OS threads.
Bạn có thể điều chỉnh số lượng
P
bằng cách thiết lập biến môi trườngGOMAXPROCS
.
🔄 Về goroutine:
- Có thể tạo hàng nghìn đến hàng triệu goroutines.
- Goroutine rất nhẹ (khoảng 2KB stack ban đầu, tự mở rộng).
- Điều kiện duy nhất: đủ bộ nhớ.
5. Go Scheduler — Under The Hood
🧩 P (Processor)
- Gắn với một
M
- Có Local Run Queue (tối đa 256 goroutines)
- Điều phối việc thực thi goroutines
🧵 M (Machine - OS Thread)
- Là OS thread thực sự
- Go runtime quản lý số lượng
M
tùy theo tải
🌐 Global Run Queue
- Nơi chứa các goroutine chưa phân phối cho
P
- Nếu local queue của
P
trống → lấy từ Global Queue
🔧 Khi tạo goroutine mới
- Go tạo struct
G
(Goroutine) - G sẽ được:
- Đưa vào Local Run Queue nếu còn chỗ
- Hoặc Global Run Queue nếu local queue đầy
6. Work Stealing — Trộm việc để cân bằng
- Mỗi
P
thực thi các goroutine trong local queue. - Nếu local queue trống:
P
sẽ "đánh cắp" ½ số goroutine từ local queue củaP
khác.- Nếu không có gì để "trộm" → lấy từ Global Run Queue.
✅ Kỹ thuật này giúp cân bằng tải và tận dụng CPU hiệu quả.
7. Blocking Calls — Khi goroutine bị chặn
Khi một goroutine gọi I/O, mạng, channel,...:
- Goroutine sẽ bị descheduled
- Chuyển sang trạng thái
Blocked
- Nhường tài nguyên cho goroutine khác
🛰 Ví dụ: chờ network
- Goroutine chờ phản hồi mạng → đưa vào
Network Queue
- Một background thread giám sát queue này
- Khi xong → goroutine được đưa lại vào
Runnable
8. Thu gom bộ nhớ (Garbage Collection)
- Khi goroutine kết thúc hoặc không còn tham chiếu đến → được GC thu gom
- Tránh rò rỉ bộ nhớ (memory leak)
📚 Tài liệu tham khảo
🧠 Kết luận
Go Scheduler là một hệ thống cực kỳ tối ưu, tự động và hiệu quả. Nó cho phép:
- Viết các chương trình concurrent dễ dàng, không đau đầu quản lý thread
- Khả năng mở rộng lớn nhờ lightweight goroutine
- Xử lý I/O non-blocking một cách tự nhiên
Việc hiểu cách hoạt động "under the hood" sẽ giúp bạn:
- Viết code tối ưu hơn
- Tránh các lỗi khó chịu như deadlock, starvation
- Debug hiệu quả hơn trong hệ thống lớn
Cảm ơn Chatgpt đã giúp mình tạo nên markdown đẹp