
go 程序中启动 goroutine 后立即退出 main 函数,会导致程序提前终止,新协程来不及执行——这是并发无输出的最根本原因。
在 Go 中,main 函数的返回即代表整个程序的结束。一旦 main 执行完毕,运行时会强制终止所有仍在运行的 goroutine(包括尚未调度或正在执行的),不会等待它们完成。你提供的代码正是这一问题的典型示例:
func main() {
h := &Hello{100}
go h.Myprint("need to go") // 启动 goroutine,但 main 随即结束
} // ← 程序在此处退出,goroutine 被强制终止,fmt.Println 从未执行虽然 Myprint 内部使用 go func(){...}() 启动了协程,但 main 函数本身没有做任何等待,导致整个进程瞬间退出。
✅ 正确做法:确保主 goroutine 等待子 goroutine 完成
最常用、最推荐的方式是使用 sync.WaitGroup:
package main
import (
"fmt"
"sync"
"time"
)
type Hello struct {
a int
}
func (h *Hello) Myprint(value string, wg *sync.WaitGroup) {
defer wg.Done() // 标记该 goroutine 已完成
fmt.Println(value)
}
func main() {
h := &Hello{100}
var wg sync.WaitGroup
wg.Add(1)
go h.Myprint("need to go", &wg)
wg.Wait() // 主 goroutine 阻塞,直到所有 wg.Done() 被调用
}✅ 输出:need to go
⚠️ 其他不推荐但可验证的临时方式(仅用于学习)
-
加 time.Sleep(不推荐生产环境):
go h.Myprint("need to go") time.Sleep(10 * time.Millisecond) // 强制延时,依赖运气,不可靠 -
使用通道同步(适合有返回值场景):
done := make(chan bool) go func() { h.Myprint("need to go") done <- true }() <-done // 等待信号
? 关键要点总结
- Goroutine 是轻量级线程,但生命周期不被自动管理;Go 不提供“守护协程”概念。
- main 函数结束 = 整个进程退出,所有 goroutine 会被立即回收,无论是否执行完毕。
- 永远不要依赖 Sleep 做同步;应使用 sync.WaitGroup(无返回值)、channel(需通信/返回值)或 context(带超时/取消)等显式同步机制。
- 方法接收者(如 *Hello)在 goroutine 中可安全使用,只要其底层数据在 goroutine 生命周期内有效(本例中 h 是局部变量,但因 main 退出太快,实际未涉及逃逸问题;真正要注意的是避免在 goroutine 中引用已释放的栈变量——本例不触发此风险)。
掌握这一基础行为,是写出可靠 Go 并发程序的第一步。










