
go 程序在 `main` 函数返回后立即退出,若未等待启动的 goroutine 执行完成,其内部操作(如打印)将被强制终止,导致无输出。
在您提供的代码中,main 函数调用 go h.Myprint("need to go") 启动一个 goroutine,但随后函数立即结束,整个程序进程随之终止——此时 Myprint 内部启动的匿名 goroutine 甚至来不及调度执行 fmt.Println,就被系统回收了。
根本问题不在于“方法不能并发调用”,而在于缺少同步机制。Go 的并发模型要求显式协调 goroutine 的生命周期,尤其是主 goroutine(即 main)必须主动等待其他 goroutine 完成,否则程序会提前退出。
✅ 正确做法:使用 sync.WaitGroup 实现等待:
package main
import (
"fmt"
"sync"
)
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) // 告知 WaitGroup 将等待 1 个 goroutine
go h.Myprint("need to go", &wg) // 传入指针以便修改
wg.Wait() // 阻塞,直到所有 Add 的 goroutine 调用 Done()
}? 关键要点:
- sync.WaitGroup 是 Go 标准库中最常用、最轻量的 goroutine 同步工具;
- Add(1) 必须在 go 语句之前调用,避免竞态(如 Add 和 Done 顺序错乱);
- defer wg.Done() 确保函数退出时自动通知等待组;
- 不要依赖 time.Sleep 替代同步——它不可靠、不精确,且违背 Go 的并发设计哲学。
⚠️ 补充提醒:
若 Myprint 方法需被多次并发调用,可将 WaitGroup 的管理逻辑上移至 main(如循环中 Add 多次),或封装为更健壮的并发执行器。但切记:所有由 go 启动的协程,都必须有明确的退出等待路径,否则就是潜在的“幽灵 goroutine”风险。
掌握 WaitGroup 是写出可靠 Go 并发程序的第一步,也是理解 Go “不要通过共享内存来通信,而应通过通信来共享内存”理念的实践起点。










