time.Sleep仅阻塞当前goroutine,其他goroutine仍运行;单位必须显式指定如time.Second,避免误写为纳秒;不可取消,需中断时应使用time.AfterFunc或time.NewTimer。

time.Sleep 会阻塞当前 goroutine,不是整个程序
这是最常被误解的一点:time.Sleep 只会让调用它的那个 goroutine 暂停,其他 goroutine 照常运行。如果你在 main 函数里直接调用它,看起来像“程序卡住”,其实是 main goroutine 在等,而其他启动的 goroutine(比如用 go func() {...}() 启动的)仍可执行。
- 适合场景:单次等待、简单轮询、测试模拟延时
- 不适合场景:高并发下频繁调用(易堆积 goroutine)、需要精确唤醒或取消的逻辑
- 参数单位是
time.Duration,必须显式转换,比如time.Second、time.Millisecond * 500
别直接写 time.Sleep(1000),单位错误会导致休眠 1000 纳秒
Go 的 time.Sleep 接收的是 time.Duration 类型,底层是 int64,单位为纳秒。写数字字面量不加单位后缀,会被当作纳秒处理——time.Sleep(1000) 实际只休眠 1 微秒(1000 纳秒),远小于预期。
- 正确写法:
time.Sleep(1 * time.Second)、time.Sleep(500 * time.Millisecond) - 常见错误:
time.Sleep(1000)、time.Sleep(5)(都极短,难调试) - 推荐用
time.Second等常量,避免手算和精度丢失
需要可取消延时?改用 time.AfterFunc 或 time.NewTimer
time.Sleep 不可中断;一旦开始,只能等完。若需响应外部信号(如用户中断、超时控制、上下文取消),应避开 time.Sleep,改用带 channel 的机制。
-
time.AfterFunc(d, f):延时后执行函数,返回的*Timer可调用Stop()取消 timer := time.NewTimer(2 * time.Second); select { case :配合select实现可取消等待- 注意:
time.After(d)返回的 channel 无法取消,仅适用于“一次性、不可撤回”的延时
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) defer cancel()timer := time.NewTimer(5 * time.Second) defer timer.Stop()
select { case <-timer.C: fmt.Println("delay completed") case <-ctx.Done(): fmt.Println("canceled due to timeout") }
在循环中用 time.Sleep 要防时间漂移
如果写一个每秒执行一次的任务:for { doWork(); time.Sleep(time.Second) },实际间隔会略大于 1 秒(因为 doWork() 耗时也被计入)。长期运行可能越拖越慢。
立即学习“go语言免费学习笔记(深入)”;
- 解决办法:用“固定起始时间 + 下次触发点”方式对齐,例如记录
next := time.Now().Add(time.Second),每次time.Sleep(next.Sub(time.Now())),再更新next - 更稳妥方案:用
time.Ticker,它内部已处理时钟漂移校准 -
time.Ticker不适合单次延时,但循环定时任务首选它
真正要注意的不是“怎么睡”,而是“谁在睡、能不能醒、醒了之后还准不准”。尤其在服务端或 CLI 工具里混用 time.Sleep 和 context 控制时,漏掉取消路径很容易导致 goroutine 泄漏或响应僵死。










