goroutine 是一个轻量级的、并发执行的函数,由 Go 运行时进行管理。启动一个很简单——只需在函数调用前加上 go。Goroutine 是 Go 的标志性并发特性——远比操作系统线程便宜,所以你可以运行数千个或数百万个。
启动 goroutine
{
fmt.Println()
}
sayHello()
{
fmt.Println()
}()
go 关键字在新的 goroutine 上启动该函数并立即返回——调用代码继续执行而无需等待。
OS thread: ~1–2 MB of memory each → thousands max
Goroutine: ~2 KB initial stack (grows as needed) → MILLIONS feasible
The Go runtime SCHEDULES many goroutines onto a small pool of OS threads (M:N).
Goroutine 不是操作系统线程——Go 调度器将许多 goroutine 多路复用到少数几个操作系统线程上。这使得它们异常便宜,能够实现大规模并发(例如,在处理数百万连接的服务器中,为每个连接启动一个 goroutine)。
func main() {
go sayHello() // ❌ main might EXIT before this goroutine runs → nothing printed
// program ends immediately
}
当 main 返回时,程序结束——会杀死任何仍在运行的 goroutine。你需要进行协调。
var wg sync.WaitGroup
for i := 0; i < 3; i++ {
wg.Add(1) // increment the counter
go func(n int) {
defer wg.Done() // decrement when this goroutine finishes
fmt.Println("worker", n)
}(i) // pass i as an argument (avoid the loop-var capture bug)
}
wg.Wait() // BLOCK until all goroutines call Done()
sync.WaitGroup 是等待一组 goroutine 完成的标准方式。
ch := make(chan string)
go func() { ch <- "result" }() // send a result on the channel
msg := <-ch // receive (blocks until a value arrives)
Go 的哲学:"不要通过共享内存来通信;通过通信来共享内存"——使用 channel 在 goroutine 之间传递数据,而不是使用共享变量和锁。
Goroutine 是 Go 的定义特性,也是它在并发、网络系统中表现出色的主要原因。
It 的极端轻量级特性(相对于线程的千字节 vs 兆字节,以及在操作系统线程上的 M:N 调度)使大规模并发变得实用和简单——服务器可以为每个请求或连接启动一个 goroutine,而无需担心资源,这对于操作系统线程来说是困难或不可能的。
理解如何启动它们(go)、同步 的关键需求(main 退出会杀死 goroutine;使用 WaitGroup 来等待)以及 Go 倾向于通过 channel 通信 而不是共享内存,这对于编写正确的并发 Go 代码是基础性的。
Goroutine(及其周围的模式)是 Go 价值主张的核心,是该语言中最重要的和最频繁被测试的主题之一。