
go程序在main函数返回后立即退出,不会等待其他goroutine执行完毕;因此若未显式同步,启动的goroutine可能被强制终止,导致输出不稳定。
go程序在main函数返回后立即退出,不会等待其他goroutine执行完毕;因此若未显式同步,启动的goroutine可能被强制终止,导致输出不稳定。
在Go语言中,goroutine是轻量级并发执行单元,但其生命周期不独立于主程序。关键规则是:当main函数执行结束(即main goroutine退出)时,整个程序立即终止,所有其他正在运行或尚未开始的goroutine都会被强制停止,且不会执行defer语句、不会清理资源。
这正是你遇到“随机行为”的根本原因:
func main() {
fmt.Println("Hello Good Morning")
go t(1) // 启动新goroutine,但无任何等待机制
t1(2) // 主goroutine同步执行t1
time.Sleep(5) // ⚠️ 错误!单位是纳秒(非秒),实际仅暂停5纳秒
fmt.Println("End of func main")
}上述代码中 time.Sleep(5) 实际休眠时间极短(5纳秒),远不足以让 t(1) 中的 time.Sleep(1)(即1纳秒?不——此处更严重:time.Sleep(1) 缺少单位,*会被解释为 `time.Sleep(1 time.Nanosecond)**),导致main函数几乎立刻结束,go t(1)` 极大概率被截断。
✅ 正确做法一:使用带单位的 time.Sleep 显式延时
必须明确指定时间单位,例如 time.Second:
func main() {
fmt.Println("Hello Good Morning")
go t(1)
t1(2)
time.Sleep(2 * time.Second) // 确保足够等待goroutine完成
fmt.Println("End of func main")
}
func t(i int) {
fmt.Println("In func t")
time.Sleep(1 * time.Second) // 修正:显式写明单位
}✅ 正确做法二(推荐):使用 sync.WaitGroup 实现精确同步WaitGroup 是更健壮、可扩展的同步方式,尤其适用于多个goroutine协作场景:
立即学习“go语言免费学习笔记(深入)”;
package main
import (
"fmt"
"sync"
"time"
)
func t(i int, wg *sync.WaitGroup) {
defer wg.Done() // 标记当前goroutine完成
fmt.Println("In func t")
time.Sleep(1 * time.Second)
}
func t1(i int, wg *sync.WaitGroup) {
defer wg.Done()
fmt.Println("In func t1")
time.Sleep(1 * time.Second)
}
func main() {
var wg sync.WaitGroup
fmt.Println("Hello Good Morning")
wg.Add(1)
go t(1, &wg)
wg.Add(1)
go t1(2, &wg) // 注意:t1也应作为goroutine启动,保持并发语义一致
wg.Wait() // 阻塞直到所有Add的goroutine调用Done()
fmt.Println("End of func main")
}? 关键注意事项:
-
time.Sleep(n)中n是time.Duration类型,必须带单位(如time.Second,time.Millisecond),否则默认为纳秒,极易引发逻辑错误; -
main函数不是“主线程”而是“主goroutine”,它的退出 = 整个进程退出; -
WaitGroup要求Add()在go语句前调用,且Done()必须确保执行(建议用defer); - 不要依赖
time.Sleep做生产环境的同步手段——它不可靠、不精确、难以维护;WaitGroup、channel或context才是符合Go并发哲学的正确工具。
掌握这一机制,是写出可靠Go并发程序的第一步:goroutine不会自动“被等待”,你必须主动协调它们的生命周期。


















