<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Timer on 我的技术博客</title><link>https://buvidk1234.github.io/tags/timer/</link><description>Recent content in Timer on 我的技术博客</description><generator>Hugo</generator><language>zh-cn</language><lastBuildDate>Tue, 18 Aug 2026 00:19:00 +0800</lastBuildDate><atom:link href="https://buvidk1234.github.io/tags/timer/index.xml" rel="self" type="application/rss+xml"/><item><title>Go Runtime（十）：Timer实现</title><link>https://buvidk1234.github.io/posts/go-runtime-10-timer/</link><pubDate>Tue, 18 Aug 2026 00:19:00 +0800</pubDate><guid>https://buvidk1234.github.io/posts/go-runtime-10-timer/</guid><description>&lt;blockquote&gt;
&lt;p&gt;本文源码基线为 &lt;strong&gt;Go 1.26.2、Linux/amd64&lt;/strong&gt;。Go 1.23 重写了 Timer Channel 的可回收性与 Stop/Reset 保证；阅读旧版本分析时必须先确认版本边界。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Timer 不是一个独立后台 goroutine 加一张全局表。Go 1.26 把真实时间 Timer 组织在每个 P 的四叉最小堆中，由调度器和 netpoll 共同决定睡到何时、何时执行到期回调。&lt;/p&gt;
&lt;p&gt;它同时服务 &lt;code&gt;time.Sleep&lt;/code&gt;、&lt;code&gt;time.Timer&lt;/code&gt;、&lt;code&gt;time.Ticker&lt;/code&gt;、&lt;code&gt;AfterFunc&lt;/code&gt; 和网络 Deadline。难点不只是“按时间排序”，而是并发 Stop/Reset、跨 P 修改、周期跳期、Channel 旧值以及 GC 可达性。&lt;/p&gt;
&lt;h2 id="time包如何进入runtime"&gt;time包如何进入runtime&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;time&lt;/code&gt; 包通过 runtime 提供的私有入口创建和修改 Timer：&lt;/p&gt;
&lt;details class="code-fold" open&gt;
&lt;summary&gt;TEXT&lt;/summary&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;time.Sleep -&amp;gt; runtime.timeSleep
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;time.NewTimer -&amp;gt; runtime.newTimer(sendTime, channel)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Timer.Stop -&amp;gt; runtime.stopTimer
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Timer.Reset -&amp;gt; runtime.resetTimer
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;time.AfterFunc -&amp;gt; runtime.newTimer(goFunc, nil)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;net deadline -&amp;gt; runtime timer callback&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/details&gt;
&lt;p&gt;&lt;a href="https://github.com/golang/go/blob/go1.26.2/src/time/sleep.go#L143"&gt;&lt;code&gt;time.NewTimer&lt;/code&gt;&lt;/a&gt; 的源码仍写 &lt;code&gt;make(chan Time, 1)&lt;/code&gt;。默认模式下 runtime 借助 &lt;code&gt;hchan.timer&lt;/code&gt; 对外呈现同步、容量为零的语义；设置 &lt;code&gt;GODEBUG=asynctimerchan=1&lt;/code&gt; 才恢复 Go 1.23 以前的异步 Timer Channel 行为。因此不能只看 &lt;code&gt;make&lt;/code&gt; 参数推断 &lt;code&gt;cap(t.C)&lt;/code&gt; 和 Stop/Reset 语义。&lt;/p&gt;</description></item></channel></rss>