goroutine本质是加go前缀启动函数,但需同步控制、显式传参、配合channel或WaitGroup;应避免匿名函数立即执行,改用命名函数调用,并警惕循环中闭包捕获变量陷阱。

goroutine 本质就是加个 go 前缀启动函数,但不加同步控制就跑飞、不传参就闭包踩坑、不配 channel 或 sync.WaitGroup 就收不到结果——它极简,也极容易“看似在跑,其实没跑完”。
怎么启动 goroutine:别写 go func() { ... }(),直接调函数
新手常把 goroutine 启动写成匿名函数立即执行的形式,比如:
go func() {
fmt.Println("hello")
}()这没错,但多数时候是画蛇添足。真正该做的是:把逻辑封装成普通函数,用 go 调用它。
- 更清晰:函数名自带语义,便于测试和复用
- 更安全:避免闭包捕获循环变量(见下节)
- 更可控:参数显式传递,栈隔离明确
✅ 正确姿势:
立即学习“go语言免费学习笔记(深入)”;
func say(msg string) {
fmt.Println(msg)
}
func main() {
go say("hello from goroutine")
time.Sleep(10 * time.Millisecond) // 临时保命,实际要用 wait 或 channel
}
for 循环里启多个 goroutine:闭包陷阱必须破
下面这段代码几乎 100% 输出全是 3:
for i := 0; i < 3; i++ {
go func() {
fmt.Println(i) // 全部打印 3!
}()
}原因:所有 goroutine 共享同一个变量 i 的地址,等它们真正执行时,for 早已结束,i == 3。
- ❌ 错误解法:不传参、不复制、只靠
time.Sleep拖延 - ✅ 解法一:把
i当参数传进去(推荐)
for i := 0; i < 3; i++ {
go func(val int) {
fmt.Println(val) // 输出 0, 1, 2
}(i)
}- ✅ 解法二:在循环内重新声明变量(效果等价)
for i := 0; i < 3; i++ {
i := i // 新建局部变量
go func() {
fmt.Println(i) // 输出 0, 1, 2
}()
}怎么等 goroutine 结束:别靠 time.Sleep,用 sync.WaitGroup 或 channel
time.Sleep 是调试玩具,生产环境绝对不能用——它既不准(可能等不够或等太久),也不可靠(CPU 负载高时调度延迟变大)。
- ✅ 场景一:只关心“全部完成”,不关心返回值 → 用
sync.WaitGroup
func worker(id int, wg *sync.WaitGroup) {
defer wg.Done()
fmt.Printf("worker %d done\n", id)
}
func main() {
var wg sync.WaitGroup
for i := 1; i <= 3; i++ {
wg.Add(1)
go worker(i, &wg)
}
wg.Wait() // 阻塞直到所有 Done()
}
- ✅ 场景二:要拿结果、要控制流、要解耦 → 用
chan
c := make(chan int, 3)
go func() { c <- 42 }()
go func() { c <- 100 }()
go func() { c <- -1 }()
// 收三个数(带缓冲可非阻塞)
fmt.Println(<-c, <-c, <-c)goroutine 和 channel 组合:别漏 close,别让 range 卡死
用 for range ch 接收 channel 数据时,如果没人关 channel,接收方会永远阻塞在 range 上——哪怕所有发送 goroutine 已退出。
- ❌ 错误:只发不关
ch := make(chan int)
go func() { ch <- 1; ch <- 2 }() // 没 close!
for v := range ch { // 这里卡住,死锁
fmt.Println(v)
}- ✅ 正确:发送方完成前调用
close(ch),且确保只关一次
ch := make(chan int)
go func() {
ch <- 1
ch <- 2
close(ch) // 关键!
}()
for v := range ch { // 安全退出
fmt.Println(v)
}真正难的不是语法,而是谁负责关闭、什么时候关、并发关闭是否重复——这些得结合业务生命周期设计,不是加一行 close 就万事大吉。










