Go 语言的并发模型是其最显著的语言特性之一。Goroutine 是 Go 实现并发的核心机制,它比线程更轻量,调度效率极高。
本章将带你了解 Goroutine 的基本概念、创建方式以及背后的调度机制。
一、什么是 Goroutine?
Goroutine 是由 Go 运行时(runtime)管理的轻量级线程。
特点:
- • 启动快:创建成本远小于线程
- • 占用小:初始栈大小仅约 2 KB,按需增长
- • 数量多:支持成千上万个 Goroutine 并发运行
- • 自动调度:由 Go runtime 自动调度到多个线程上执行
二、创建 Goroutine
创建一个 Goroutine 非常简单,只需使用 go
关键字:
scss
func sayHello() {
fmt.Println("Hello from Goroutine")
}
func main() {
go sayHello() // 启动一个新的 Goroutine
fmt.Println("Main function")
time.Sleep(time.Second) // 等待子协程执行完毕
}
运行效果(输出可能顺序不定):
css
Main function
Hello from Goroutine
注意:主 Goroutine 退出时,程序将直接终止,其他 Goroutine 即使未完成也会被强制结束。
三、匿名函数启动 Goroutine
可以使用匿名函数快速创建 Goroutine:
go
go func(name string) {
fmt.Println("Hello,", name)
}("Go")
四、Goroutine 的调度模型
Go 使用M:N 调度模型:
- • M(Machine):操作系统线程(OS Thread)
- • G(Goroutine):用户级协程
- • P(Processor):逻辑处理器,调度器的核心
调度器作用:
- • 把成千上万个 G 映射到有限的 M 上
- • 利用 P 控制并发度(由
GOMAXPROCS
控制)
你可以通过设置 GOMAXPROCS
控制最大并发线程数:
scss
runtime.GOMAXPROCS(2)
默认值为当前机器 CPU 核数。
五、调度器工作方式简要流程
-
- 创建 Goroutine 后,进入可运行队列
-
- 调度器从队列中取出 Goroutine 并分配给线程执行
-
- 阻塞操作(如 IO)会让线程挂起并调度其他 Goroutine
-
- 非抢占式调度 + 安全点机制(某些点才能切换)
六、调试与观察 Goroutine
可以使用 runtime
包查看当前 Goroutine 数量:
less
fmt.Println("Goroutine数量:", runtime.NumGoroutine())
使用 go tool pprof
或第三方工具(如 delve)分析 Goroutine 状态。
七、使用场景举例
- • 高并发 Web 服务器处理请求
- • 定时任务并发执行
- • 异步日志写入
- • 并发爬虫
八、小结
特性 | 说明 |
---|---|
创建方式 | 使用 go 关键字 |
性能 | 数量轻量、栈空间动态增长 |
调度机制 | M:N 多对多调度,由 runtime 管理 |
并发优势 | 快速、高效、代码简洁 |