- vừa được xem lúc

Go Scheduler — Cách Golang quản lý và vận hành Goroutine một cách hiệu quả

0 0 1

Người đăng: Hoang Le

Theo Viblo Asia

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 qua P

⚙️ 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ường GOMAXPROCS.


🔄 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ủa P 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

Bình luận

Bài viết tương tự

- vừa được xem lúc

Create Certificates, Identifiers & Profiles App IOS

Mở đầu. Xin chào các bạn hôm này mình sẽ giới thiệu cho các bạn một cách tạo certificates, identifiers & profiles với tài khoản Apple Developer. Có tài khoản Apple Developer. Ai chưa có thì không cần đọc tiếp nha :.

0 0 51

- vừa được xem lúc

Chương 5 Object oriented programming

Chương 5 Object oriented programming. Tôi lần đầu tiên được giới thiệu về lập trình hướng đối tượng ở trường cao đẳng nơi tôi đã có một giới thiệu tóm tắc về c++.

0 0 39

- vừa được xem lúc

Hướng dẫn tạo link tracking nguồn cài đặt cho mobile app (xác định nguồn cài đặt cho mobile app)

Giới thiệu. Bạn đang chạy quá nhiều campaign cho ứng dụng mobile từ các mạng xã hội: facebook, twitter, ... các chiến dịch offline cũng như các chiến dịch online của bên thứ 3. Bạn không thể xác định được nguồn nào mang cho mình lượng install cao nhất. Vì nếu dùng shortlink thì chỉ đo được lượt clic

0 0 49

- vừa được xem lúc

SwiftUi: Bắt đầu từ những điều căn bản nhất. Phần 1

Trong bài này, bạn sẽ được tìm hiểu về việc tạo ra giao diện bằng việc khai báo và tuỳ chỉnh views, cách sử dụng các biến trạng thái để cập nhật giao diện thay vì dùng code. Tập sử dụng tính năng new preview và live preview, những trải nghiệm thú vị khi làm việc cùng với code và WYSIWYG layout.

0 0 78

- vừa được xem lúc

Những điều khác nhau cần biết giữa thiết kế ứng dụng Android và ứng dung iOS

Để tạo ra ứng dụng có trải nghiệm tốt nhất, tương thích với dòng thiết bị, bạn nên ghi nhớ sự khác biệt giữa 2 nền tảng iOS và Android. Các ứng dụng này không chỉ khác nhau ở phần trông như thế nào, chúng cũng khác nhau về cấu trúc và luồng ứng dụng.

0 0 41

- vừa được xem lúc

Những khó khăn khi làm dự án maintain ( dưới góc nhìn của một React Native Developer)

Đi làm một vài năm ở công ty outsource, minh thấy hầu như các anh em đều khá e ngại với các dự án maintain, nhất là thuộc hàng code "siêu thối", spec thuộc loại "siêu to khổng lồ ",... Và mình cũng thế, mình cũng đang "theo đuổi" một chú em với "chức năng siêu to kh

0 0 328