模块 7 · 第 1 课(共 5)课程中的31/50~12 min
模块课程(1/5)
Goroutine:轻量级并行
goroutine 是 Go 管理的并发执行单元
运行时。您可以在函数前面使用 go 关键字启动一个
致电:
Go
go greet("Anna") // chiamata a funzione esistente
go func() { // funzione anonima
fmt.Println("hi")
}()go 语句立即返回:goroutine 开始于
并行,调用者继续。
为什么它们是“轻量级”
- 初始堆栈 ~2KB(动态增长,如果需要,可达数百 MB)。
- 通过运行时 (
GOMAXPROCS) 多路复用到少量操作系统线程上。 - 数千/数百万个 goroutine 是常规的;对于操作系统线程来说,这是不可能的。
从概念上讲,它是“并发的即发即弃”,但随着所有
用于协调的惯用工具(通道、sync.WaitGroup、
context)。
主要不等待
Go
func main() {
go func() { fmt.Println("ciao dalla goroutine") }()
// main esce subito: niente garanzia che la goroutine completi
}当 main 返回时,进程终止:goroutines 不会得到
为了“完成他们的工作”,他们只是和
过程。需要显式同步。
同步:预览
您将在下一课程中看到的三个工具:
Go
// 1) Channel: la goroutine "segnala" via canale
done := make(chan struct{})
go func() {
work()
done <- struct{}{}
}()
<-done // attendi
// 2) sync.WaitGroup: N goroutine
var wg sync.WaitGroup
wg.Add(1)
go func() { defer wg.Done(); work() }()
wg.Wait()
// 3) context: cancellazione/timeout propagati“经典”闭环错误
在 Go 1.21 之前,这是一个常见的问题:
Go
for i := 0; i < 3; i++ {
go func() { fmt.Println(i) }() // stampa "3 3 3" su versioni vecchie
}从 Go 1.22 for 变量是在每个
迭代,所以默认情况下修复了该错误。在较旧的代码库中,您将
仍然看到修复模式:
Go
for i := 0; i < 3; i++ {
i := i // shadow esplicito
go func() { fmt.Println(i) }()
}
// oppure passa come argomento:
for i := 0; i < 3; i++ {
go func(n int) { fmt.Println(n) }(i)
}Goroutine != 操作系统线程
| 方面 | 协程 | 操作系统线程 |
|---|---|---|
| 初始堆栈 | ~2 KB | 1–8 MB(开始时分配) |
| 创作 | 纳秒 | 微秒 |
| 日程安排 | Go 运行时(合作) | 内核(抢占式) |
| 实用计数 | 10万+ | 几千 |
单个操作系统线程可以托管多个 goroutine。运行时移动 需要时跨线程的 goroutine。
尝试一下
锻炼#go.m7.l1.e1
尝试:0加载中...
将greet函数作为goroutine启动,并等待100ms,然后退出main。
正在加载编辑器...
显示提示
函数调用前面的“go”会启动 goroutine。
3 次尝试后可用的解决方案
锻炼#go.m7.l1.e2
尝试:0加载中...
启动一个匿名函数作为打印“hi”的 goroutine。
正在加载编辑器...
显示提示
匿名函数通过尾随 `()` 进行调用:`go func(){...}()`。
3 次尝试后可用的解决方案
Quiz#go.m7.l1.e3
准备好如果 main 在 goroutine 完成之前退出会发生什么?
Go
func main() {
go work()
// main ritorna immediatamente
}回顾
go f()同时启动 f();它立即返回。- Goroutine = ~2 KB 初始大小,多路复用到几个操作系统线程上。
main不等待:您需要同步(通道/等待组/上下文)。time.Sleep只是说教性的,绝不用于生产中的同步。- 从 Go 1.22 开始,
for变量在每次迭代中都是“新鲜的”(不再有“3 3 3”错误)。