Goroutine
Goroutines in Go - Comprehensive Guide
1. Goroutines là gì?
Goroutine là một đơn vị thực thi nhẹ (lightweight thread) được quản lý bởi runtime của Go, không phải hệ điều hành. Goroutines cho phép thực hiện đồng thời (concurrency) nhiều tác vụ trong một chương trình.
Đặc điểm:
Nhẹ: Một goroutine chỉ chiếm vài KB bộ nhớ (so với thread hệ điều hành chiếm MB).
Quản lý bởi Go runtime: Go scheduler phân bổ goroutines trên các thread hệ điều hành (OS threads) để tối ưu hóa hiệu năng.
Khởi tạo đơn giản: Chỉ cần từ khóa
go
trước một hàm.
Goroutines là nền tảng của mô hình concurrency trong Go, kết hợp với channels để đồng bộ và giao tiếp.
Ví dụ cơ bản:
Lưu ý:
time.Sleep
chỉ để minh họa. Trong thực tế, nên dùng cơ chế đồng bộ như channels hoặcsync.WaitGroup
.
2. Cách hoạt động của Goroutines
Go Scheduler:
Go runtime có một scheduler (dựa trên mô hình M:N) ánh xạ nhiều goroutines (M) lên ít thread hệ điều hành (N).
Scheduler sử dụng cơ chế preemptive scheduling (từ Go 1.14) để ngăn goroutines chiếm CPU quá lâu.
Các điểm tạm dừng (yield points) bao gồm: gọi hàm, I/O, channel operations, hoặc garbage collection.
Stack: Mỗi goroutine bắt đầu với stack nhỏ (~2KB) và tự động mở rộng nếu cần (lên đến 1GB).
Ví dụ minh họa scheduler:
Kết quả: Các goroutine chạy xen kẽ do scheduler điều phối.
3. Khởi tạo và quản lý Goroutines
3.1. Khởi tạo Goroutine
Sử dụng từ khóa
go
trước một hàm hoặc closure:
Lưu ý: Goroutine chạy ngay lập tức nhưng không đảm bảo thứ tự hoàn thành.
3.2. Đồng bộ Goroutines
Goroutines không tự đợi nhau. Để đồng bộ, sử dụng:
a. sync.WaitGroup
Dùng để đợi một nhóm goroutines hoàn thành.
Mẹo:
Gọi
wg.Add(1)
trướcgo
để tránh race condition.Truyền
&wg
để chia sẻWaitGroup
.
b. Channels
Channels là cách chính để giao tiếp và đồng bộ giữa goroutines (xem chi tiết ở phần 5).
4. Goroutines và Concurrency Patterns
4.1. Worker Pool
Tạo một nhóm goroutines cố định để xử lý công việc từ một kênh.
Ưu điểm: Giới hạn số lượng goroutines, tránh tiêu tốn tài nguyên.
4.2. Fan-out/Fan-in
Phân chia công việc cho nhiều goroutines (fan-out) và thu thập kết quả (fan-in).
Ứng dụng: Xử lý song song các tác vụ độc lập (như gọi API, xử lý file).
4.3. Pipeline
Xây dựng một chuỗi xử lý dữ liệu qua nhiều giai đoạn.
Ưu điểm: Tăng tính tái sử dụng và dễ mở rộng.
5. Channels và Goroutines
Channels là cơ chế chính để giao tiếp giữa goroutines, đảm bảo an toàn (thread-safe).
Các loại channel:
Unbuffered: Đồng bộ, gửi và nhận phải xảy ra cùng lúc.
Buffered: Không đồng bộ, có thể chứa một số lượng giá trị.
Ví dụ unbuffered channel:
Ví dụ buffered channel:
Mẹo:
Đóng channel (
close(ch)
) khi không còn dữ liệu để gửi.Kiểm tra channel đóng bằng cú pháp:
v, ok := <-ch
.
6. Error Handling trong Goroutines
Goroutines chạy độc lập, nên lỗi trong một goroutine không tự động dừng chương trình.
Cách xử lý lỗi:
Truyền lỗi qua channel.
Sử dụng
panic
vàrecover
(hiếm dùng).
Ví dụ xử lý lỗi:
Mẹo: Dùng channel để thu thập lỗi từ nhiều goroutines.
7. Tối ưu hóa Goroutines
7.1. Giới hạn số lượng Goroutines
Tạo quá nhiều goroutines có thể tiêu tốn bộ nhớ và CPU.
Sử dụng worker pool hoặc semaphore để giới hạn.
Ví dụ semaphore:
7.2. Tránh Goroutine Leak
Goroutine leak xảy ra khi goroutine không bao giờ kết thúc, gây rò rỉ tài nguyên.
Ví dụ leak:
Cách sửa:
Mẹo: Sử dụng
context
để hủy goroutines khi không cần.
7.3. Tối ưu hiệu năng
GOMAXPROCS: Điều chỉnh số thread hệ điều hành bằng
runtime.GOMAXPROCS(n)
. Mặc định bằng số CPU core.Profile: Dùng
pprof
để tìm bottleneck trong concurrency.Buffered vs Unbuffered: Chọn loại channel phù hợp để giảm blocking.
8. Những lỗi thường gặp
Data Race:
Nhiều goroutines truy cập cùng biến mà không có đồng bộ.
Sửa: Dùng mutex hoặc channel.
Debug: Chạy với
-race
(go run -race
).
Goroutine Leak:
Không đóng channel hoặc goroutine chờ mãi.
Sửa: Dùng
context
hoặc đảm bảo channel được đóng.
Deadlock:
Các goroutines chờ nhau mãi.
Sửa: Kiểm tra logic channel và dùng
select
với default case.
Sử dụng
time.Sleep
để đồng bộ:Không đáng tin cậy.
Sửa: Dùng
WaitGroup
hoặc channel.
9. Ứng dụng thực tế
API Server: Gọi nhiều API song song bằng goroutines.
Data Processing: Xử lý file lớn hoặc dữ liệu streaming.
Web Crawler: Thu thập dữ liệu từ nhiều URL đồng thời.
Real-time Systems: Xử lý websocket, chat, hoặc monitoring.
Ví dụ API song song:
11. Tài liệu tham khảo
Công cụ:
go tool pprof
,go run -race
.
Last updated