go后必须跟函数调用f()而非函数名f,因goroutine调度需执行动作而非函数值;main退出会强制终止所有goroutine,应使用sync.waitgroup或chan同步,而非time.sleep。

go 后面必须跟函数调用,不能只写函数名;main 退出会立刻杀掉所有 goroutine,靠 time.Sleep 等是错的。
go 后面为什么不能写 f 而必须写 f()
Go 编译器把 go f 当作把函数值(即地址)当成一个 struct{} 类型传入,直接报错:cannot use f (type func()) as type struct{} in go statement。goroutine 启动的本质是“调度一个执行动作”,而 f 是值,f() 才是表达式——只有带括号的调用才触发执行逻辑,才能被运行时纳入 G 队列。
- 正确写法只有两种:
go f()(调用命名函数)、go func(){}()(立即调用匿名函数) - 想传参?必须显式闭包捕获,比如
for _, v := range items { go func(val string) { process(val) }(v) },否则所有 goroutine 共享循环变量v的最终值 - 返回值会被静默丢弃:哪怕
f()返回error或int,你也拿不到——需要结果就得用chan或传指针
main 函数退出后 goroutine 为啥没执行完就消失了
Go 程序生命周期由 main 函数控制。一旦 main 返回,运行时立刻终止所有 goroutine,不管它们是否正在发 HTTP 请求、写文件或打印日志。你看到“没输出”“日志断了”“数据库没写入”,大概率就是这个原因。
-
time.Sleep不是同步机制,只是碰运气:时长难估、不可靠、掩盖真实依赖 - 真正该用的是
sync.WaitGroup:启动前wg.Add(1),goroutine 结尾defer wg.Done(),main末尾阻塞调用wg.Wait() - 如果任务有返回值或需控制完成顺序,优先选
chan:比如results := make(chan int, len(tasks))收集结果,配合for i := 0; i
大量启动 goroutine 容易崩,怎么控数量
看似 for i := 0; i 很简单,实则危险:内存暴涨、调度延迟飙升,甚至触发 <code>runtime: out of memory。Go 的 GMP 调度器不是魔法,十万级活跃 G 仍会吃光栈内存和上下文切换资源。
- 用带缓冲的任务通道控制并发数:
taskChan := make(chan func(), 1024),再起固定数量 worker goroutine 持续range执行 - 关闭 pool 时顺序很重要:先
close(taskChan),再wg.Wait();反了的话,worker 可能永远卡在range上 - 长期任务(如 HTTP handler、定时轮询)必须监听
context.Context:不支持取消的 goroutine 就是“幽灵协程”,泄漏连接、goroutine 和内存
最常被忽略的点是:goroutine 的退出不是“自然结束”,而是被 main 强制终结;而最隐蔽的坑是循环变量复用和无节制创建——这两处一错,程序表现就完全不可预测。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











