
Go 中 time.Timer 仅触发一次,若在循环中反复读取其通道而未重置,会导致 goroutine 永久阻塞、程序死锁;应根据需求选择 Timer(单次)或 Ticker(周期性)。
go 中 time.timer 仅触发一次,若在循环中反复读取其通道而未重置,会导致 goroutine 永久阻塞、程序死锁;应根据需求选择 timer(单次)或 ticker(周期性)。
你遇到的问题根源在于对 time.Timer 行为的误解。time.Timer 并非“可重复触发的时钟”,而是一个一次性定时器:它在设定时间后向其 C 通道发送唯一一个时间值,之后该通道将永久关闭(或不再发送新值)。因此,在你的无限循环中:
t := time.NewTimer(1 * time.Minute)
for {
k := <p>第一次执行 <code> 会等待 1 分钟并成功接收一个 <code>time.Time</code> 值;但此后 <code>t.C</code> 不再有新值可读,且 <code>Timer</code> 不会自动重置——于是第二次循环时,goroutine 在 <code> 处无限等待,整个程序陷入<strong>死锁(deadlock)</strong>,<code>fmt.Println("poet")</code> 再也无法执行,控制台自然无任何输出。</code></code></p><p>✅ 正确做法取决于你的实际意图:</p>
-
若只需在 1 分钟后执行一次操作(如超时检查、延时启动),使用
Timer并配合单次消费:func main() { timer := time.NewTimer(1 * time.Minute) -
若需每分钟重复打印
"poet"(即周期性任务),必须使用time.Ticker:func main() { ticker := time.NewTicker(1 * time.Minute) defer ticker.Stop() // 重要:避免资源泄漏 for range ticker.C { // 每次收到 tick 即执行 fmt.Println("poet") } }
⚠️ 注意事项:
-
Timer无法复用,如需重复定时,应调用timer.Reset(d)(注意:Reset在 Timer 已触发或已停止时才安全;首次使用后不可直接Reset,推荐改用Ticker); - 使用
Ticker时务必调用ticker.Stop()释放底层资源(尤其在循环可能提前退出时); -
fmt.Print("%T", k)中格式动词%T用于类型推断,但此处更推荐fmt.Printf("Time type: %T, value: %v\n", k, k)辅助调试。
总结:牢记 Timer = one-shot,Ticker = recurring;误将 Timer 当作循环时钟是 Go 新手常见陷阱。选择合适工具,才能写出健壮、可预期的并发定时逻辑。










