惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
AWS News Blog
AWS News Blog
V
Vulnerabilities – Threatpost
D
Darknet – Hacking Tools, Hacker News & Cyber Security
量子位
博客园 - 叶小钗
AI
AI
T
Tor Project blog
Forbes - Security
Forbes - Security
W
WeLiveSecurity
博客园_首页
爱范儿
爱范儿
J
Java Code Geeks
B
Blog
G
GRAHAM CLULEY
aimingoo的专栏
aimingoo的专栏
Cloudbric
Cloudbric
C
CXSECURITY Database RSS Feed - CXSecurity.com
TaoSecurity Blog
TaoSecurity Blog
L
LINUX DO - 热门话题
阮一峰的网络日志
阮一峰的网络日志
有赞技术团队
有赞技术团队
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Simon Willison's Weblog
Simon Willison's Weblog
云风的 BLOG
云风的 BLOG
Google DeepMind News
Google DeepMind News
H
Help Net Security
博客园 - 三生石上(FineUI控件)
C
Cisco Blogs
C
Cybersecurity and Infrastructure Security Agency CISA
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
P
Palo Alto Networks Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Recent Commits to openclaw:main
Recent Commits to openclaw:main
博客园 - 司徒正美
The Last Watchdog
The Last Watchdog
Blog — PlanetScale
Blog — PlanetScale
T
The Blog of Author Tim Ferriss
S
Secure Thoughts
Spread Privacy
Spread Privacy
F
Fortinet All Blogs
月光博客
月光博客
大猫的无限游戏
大猫的无限游戏
S
SegmentFault 最新的问题
H
Hackread – Cybersecurity News, Data Breaches, AI and More
A
About on SuperTechFans
Security Latest
Security Latest
Webroot Blog
Webroot Blog
Scott Helme
Scott Helme
Hugging Face - Blog
Hugging Face - Blog

博客园 - daviyoung

Windows 11 22H2 安装 .NET Framework 3.5 完整教程 Agent 开发入门(一):从零构建你的第一个智能体 用 C# 开发一个解释器语言——基于《Crafting Interpreters》的实战系列(五)表达式求值 python使用plotly绘制图表 手把手搭建OPC UA服务器 图像处理库Pillow的使用:批量裁剪图片 python-docx库的使用:图片插入到word文档里 modbus(二)用NModbus4库实现Modbus tcp从站 Jenkins 容器化实践:Docker 部署与 CI/CD 流水线配置 Streamlit实战 用pycdc批量反编译pyc文件 以ENS 的 BaseRegistrarImplementation 合约为例,用web3.py调用合约 虚拟环境下安装包后,vs code仍然有下滑波浪线及显示找不到包(运行是正常的)的解决办法 Merkle Tree 用 C# 开发一个解释器语言——基于《Crafting Interpreters》的实战系列(四)可视化 语法树 Solidity开发ERC20智能合约claim token的功能 Solidity开发ERC20智能合约demo及部署到测试网 用 C# 开发一个解释器语言——基于《Crafting Interpreters》的实战系列(三)表达式的抽象语法树设计(Expr) 用 C# 开发一个解释器语言——基于《Crafting Interpreters》的实战系列(二)词法分析器
System.Threading.Timer 详细讲解
daviyoung · 2026-02-26 · via 博客园 - daviyoung

一、System.Threading.Timer 详细讲解

1. Timer 是什么?

System.Threading.Timer 是 .NET 中一个轻量级的、基于线程池的定时器。它不是创建一个长期运行的线程,而是利用操作系统的定时器机制,在指定时间后将回调函数投递到线程池执行。

2. Timer 的核心特性

// Timer 的完整构造函数
public Timer(
    TimerCallback callback,    // 回调委托
    object? state,              // 状态参数
    int dueTime,                // 首次执行前等待时间(毫秒)
    int period                  // 后续执行间隔时间(毫秒)
)

四种常用构造方式:

// 1. 单次执行,永不重复
new Timer(callback, null, 5000, Timeout.Infinite);

// 2. 立即开始,每1秒执行一次
new Timer(callback, null, 0, 1000);

// 3. 5秒后开始,每2秒执行一次
new Timer(callback, null, 5000, 2000);

// 4. 永不执行(可以后续Change)
new Timer(callback, null, Timeout.Infinite, Timeout.Infinite);

3. Timer 的生命周期

public class TimerDemo
{
    private Timer _timer;
    
    public void StartTimer()
    {
        // 创建定时器(不会阻塞)
        _timer = new Timer(DoWork, null, 5000, 1000);
        // 此时定时器已在运行,5秒后第一次触发
    }
    
    private void DoWork(object state)
    {
        // 这个代码在线程池线程中执行
        Console.WriteLine($"执行时间:{DateTime.Now}");
    }
    
    public void StopTimer()
    {
        // 释放定时器资源
        _timer?.Dispose();
    }
    
    public void ChangeTimer()
    {
        // 修改定时器:10秒后执行,然后每2秒一次
        _timer.Change(10000, 2000);
        
        // 停止定时器
        _timer.Change(Timeout.Infinite, Timeout.Infinite);
    }
}

二、Timer 的底层原理深度解析

1. 操作系统级别的定时器机制

graph TB subgraph ".NET层面" A[创建Timer对象] --> B[注册到Timer队列] B --> C[等待触发] end subgraph "操作系统层面" D[系统时钟中断] --> E[检查定时器队列] E --> F[到期?] F -->|是| G[触发完成端口] end subgraph "线程池层面" G --> H[IO完成线程] H --> I[执行回调函数] end C --> D

2. Windows 底层实现机制

在 Windows 上,.NET Timer 底层使用了 Waitable Timer Objects

// Windows 底层API(伪代码)
class WindowsTimerImplementation
{
    // Windows 内核对象
    private IntPtr _hTimer;
    
    public void CreateTimer(int dueTime, int period)
    {
        // 1. 创建可等待定时器对象
        _hTimer = CreateWaitableTimer(null, false, null);
        
        // 2. 设置定时器
        LARGE_INTEGER liDueTime;
        liDueTime.QuadPart = -dueTime * 10000; // 转换为100ns单位
        SetWaitableTimer(_hTimer, &liDueTime, period, null, null, false);
        
        // 3. 关联到线程池的完成端口
        ThreadPool.RegisterWaitForSingleObject(
            _hTimer,  // 等待的句柄
            Callback, // 触发时的回调
            null,     // 状态参数
            uint.MaxValue,  // 超时时间
            false     // 是否一次性
        );
    }
}

3. 核心工作原理流程图

sequenceDiagram participant App as 应用程序 participant Timer as Timer对象 participant OS as 操作系统 participant TP as 线程池 participant Callback as 回调函数 App->>Timer: new Timer(5000) Timer->>OS: 创建内核定时器 Note over OS: 定时器添加到系统队列 loop 每个系统时钟中断 OS->>OS: 检查所有定时器 OS->>OS: 计算最小到期时间 end Note over OS: 5秒后... OS->>TP: 定时器到期,投递到IO完成端口 TP->>TP: 从线程池获取可用线程 TP->>Callback: 在线程池线程中执行 Callback-->>App: 执行用户代码

4. 时钟中断机制

// 时钟中断频率(概念性说明)
class ClockInterruptDemo
{
    /*
     * Windows 默认时钟中断频率:
     * - 通常:每秒 64 次(每 15.625 毫秒一次)
     * - 多媒体应用:可能提高到每秒 1000 次
     * 
     * 这意味着定时器的精度受限于时钟中断频率
     */
     
    public static void TimerPrecision()
    {
        var timer = new Timer(_ =>
        {
            // 如果设置 1ms 触发,实际可能 15ms 后才触发
            Console.WriteLine($"理论精度:1ms,实际精度受系统时钟限制");
        }, null, 1, Timeout.Infinite);
    }
}

5. 时间轮算法(Timer的优化)

现代操作系统和 .NET 使用时间轮算法来高效管理大量定时器:

// 时间轮算法简化示例
class TimeWheel
{
    /*
     * 时间轮工作原理:
     * 
     * 假设有 1000 个定时器,如果每个都单独监控,效率很低
     * 时间轮将时间分成槽位(如 256 个槽)
     * 每个槽代表一个时间间隔
     * 
     * 槽0: [0-10ms] 的定时器
     * 槽1: [10-20ms] 的定时器
     * 槽2: [20-30ms] 的定时器
     * ...
     * 
     * 指针每秒移动,只检查当前槽的定时器
     * 时间复杂度从 O(n) 降到 O(1)
     */
     
    private List<Timer>[] _slots = new List<Timer>[256];
    private int _currentSlot = 0;
    
    public void AddTimer(Timer timer, int delayMs)
    {
        int slot = (delayMs / 10 + _currentSlot) % 256;
        _slots[slot].Add(timer);
    }
    
    public void Tick()
    {
        // 每次时钟中断,只检查当前槽
        foreach(var timer in _slots[_currentSlot])
        {
            ThreadPool.QueueUserWorkItem(timer.Callback);
        }
        _slots[_currentSlot].Clear();
        _currentSlot = (_currentSlot + 1) % 256;
    }
}

6. Timer 的内存布局

[StructLayout(LayoutKind.Sequential)]
class Timer
{
    // 内部字段(概念性)
    private TimerHolder _timerHolder;     // 持有实际定时器对象
    private TimerCallback _callback;       // 用户回调
    private object _state;                 // 状态对象
    private int _dueTime;                  // 延迟时间
    private int _period;                    // 间隔时间
    private bool _isDisposed;               // 是否已释放
    
    // 实际存储在内核中的信息
    // - 定时器队列链接
    // - 等待句柄
    // - 关联的完成端口
}

// Timer 的实际存储(简化版)
class TimerQueue
{
    // 全局定时器队列(单例)
    private static TimerQueue s_instance;
    
    // 使用最小堆管理所有定时器
    private MinHeap<TimerNode> _timers;
    
    // 下一个到期时间
    private int _nextTick;
}

三、与其他定时器的对比

public class TimerComparison
{
    /*
     * System.Threading.Timer 与其他定时器的区别:
     * 
     * 1. System.Timers.Timer
     *    - 包装了 Threading.Timer
     *    - 提供更简单的组件模型
     *    - 支持 ISynchronizeInvoke(WinForms/WPF)
     *    
     * 2. System.Windows.Forms.Timer
     *    - 基于 Windows 消息循环
     *    - UI 线程上执行,适合更新界面
     *    - 精度较低(约 55ms)
     *    
     * 3. System.Web.UI.Timer
     *    - AJAX 定时器
     *    - 用于 ASP.NET 的异步回发
     *    
     * 4. System.Threading.PeriodicTimer (.NET 6+)
     *    - 新的异步定时器
     *    - 支持 async/await 模式
     */
     
    public async Task PeriodicTimerDemo()
    {
        // .NET 6+ 新的定时器
        var timer = new PeriodicTimer(TimeSpan.FromSeconds(1));
        
        while (await timer.WaitForNextTickAsync())
        {
            Console.WriteLine("每秒执行一次");
        }
    }
}

四、实际应用示例

public class TimerPracticalDemo
{
    private Timer _timer;
    private int _executionCount;
    private readonly object _lock = new object();
    
    public void StartPreciseTimer()
    {
        // 高精度定时器(需要修改系统时钟精度)
        // 注意:会影响系统功耗
        Win32API.timeBeginPeriod(1); // 请求 1ms 精度
        
        _timer = new Timer(PreciseCallback, null, 0, 1);
    }
    
    private void PreciseCallback(object state)
    {
        // 避免回调重入
        if (!Monitor.TryEnter(_lock))
            return;
            
        try
        {
            var count = Interlocked.Increment(ref _executionCount);
            var actualInterval = MeasureActualInterval();
            
            // 实际间隔可能比请求的 1ms 大
            if (actualInterval > 2)
            {
                Console.WriteLine($"警告:期望1ms,实际{actualInterval}ms");
            }
        }
        finally
        {
            Monitor.Exit(_lock);
        }
    }
    
    private double MeasureActualInterval()
    {
        // 测量实际执行间隔
        return 0;
    }
    
    public void StopPreciseTimer()
    {
        _timer?.Dispose();
        Win32API.timeEndPeriod(1); // 恢复系统时钟精度
    }
}

// Windows API 声明
internal static class Win32API
{
    [DllImport("winmm.dll")]
    public static extern uint timeBeginPeriod(uint period);
    
    [DllImport("winmm.dll")]
    public static extern uint timeEndPeriod(uint period);
}