C#定时器深度对比:System.Timers.Timer vs System.Threading.Timer性能实测与选型指南
本文通过真实基准测试揭秘两种常用定时器的性能差异,助你做出最佳选择
一、C#定时器全景概览
在C#生态中,不同定时器适用于不同场景。以下是主流定时器的核心特性对比:
定时器类型 | 命名空间 | 适用场景 | 触发线程 | 精度 | 内存开销 | 依赖框架 |
---|---|---|---|---|---|---|
System.Windows.Forms.Timer | System.Windows.Forms | WinForms UI更新 | UI线程 | 低 | 中等 | Windows Forms |
System.Timers.Timer | System.Timers | 服务/组件任务 | 线程池线程 | 中高 | 高 | 通用 |
System.Threading.Timer | System.Threading | 高性能后台任务 | 线程池线程 | 高 | 极低 | 通用 |
DispatcherTimer | System.Windows.Threading | WPF/Silverlight UI | UI线程 | 低 | 中等 | WPF |
System.Web.UI.Timer | System.Web.UI | ASP.NET Web Forms | 服务端异步请求 | 低 | 高 | ASP.NET Web Forms |
二、核心对决:Timers.Timer vs Threading.Timer
1. 架构设计差异
2. 关键特性对比
特性 | System.Timers.Timer | System.Threading.Timer |
---|---|---|
触发方式 | Elapsed事件 | TimerCallback委托 |
线程模型 | 线程池线程(通过SynchronizingObject可同步到UI) | 直接在线程池线程执行 |
启停控制 | Start()/Stop()方法 | Change()方法动态调整 |
资源释放 | 实现IDisposable | 必须显式Dispose |
易用性 | ★★★★☆ (事件模式更直观) | ★★★☆☆ (需手动处理线程安全) |
内存开销 | 高(每个实例约18KB) | 极低(零内存分配) |
精度稳定性 | 中等(首次触发延迟90ms) | 高(首次触发延迟低) |
三、性能实测:BenchmarkDotNet数据揭秘
测试环境
- Runtime: .NET Framework 4.8.1 (4.8.9300.0)
- CPU: 12th Gen Intel Core i7-1260P 2.10GHz
- OS: Windows 11 22H2
基准测试代码
[SimpleJob(RuntimeMoniker.Net80)]
[MemoryDiagnoser]
public class TimerBenchmarks
{[Params(100)] public int Interval = 100;[Params(1000, 5000)] public int Duration = 5000;// 基准测试方法(完整实现见上文)[Benchmark(Baseline = true)] public int SystemTimersTimer() { ... }[Benchmark] public int SystemThreadingTimer() { ... }[Benchmark] public int TheoreticalCount() => Duration / Interval;
}
测试结果
Method | Interval | Duration | Mean | Allocated | Alloc Ratio |
---|---|---|---|---|---|
SystemTimersTimer | 100 | 1000 | 1,092,123,360.0 ns | 18896 B | 1.00 |
SystemThreadingTimer | 100 | 1000 | 1,091,974,353.3 ns | 0 B | 0.00 |
TheoreticalCount | 100 | 1000 | 0.4 ns | 0 B | 0.00 |
SystemTimersTimer | 100 | 5000 | 5,030,020,742.9 ns | 18824 B | 1.00 |
SystemThreadingTimer | 100 | 5000 | 5,029,031,946.2 ns | 0 B | 0.00 |
TheoreticalCount | 100 | 5000 | 0.4 ns | 0 B | 0.00 |
关键结论
- 时间性能几乎相同:两种定时器执行时间差异<0.01%(可忽略)
- 内存分配天壤之别:
Timers.Timer
:每次测试分配~18KB内存Threading.Timer
:零内存分配(Alloc Ratio=0)
- 精度表现:
- 首次触发延迟约90ms(两种定时器都存在)
- 长期运行精度更高(5000ms测试误差仅0.6%)
- 理论vs实际触发次数:
// 1000ms测试:理论触发10次,实际触发约10.9次 // 5000ms测试:理论触发50次,实际触发约50.3次
四、实战选型指南
1. 首选System.Threading.Timer
的场景
// 高性能后台服务示例
public class BackgroundService
{private readonly System.Threading.Timer _timer;public BackgroundService(){_timer = new System.Threading.Timer(_ => {// 1. 内存清理CleanUpMemory();// 2. 数据同步SyncDataToDatabase();// 3. 健康检查PerformHealthCheck();}, null, 0, 60_000); // 每分钟执行}
}
适用场景:
- 内存敏感型应用(如微服务、容器化应用)
- 高频触发任务(间隔<100ms)
- 无需UI交互的后台服务
- 资源受限环境(嵌入式、IoT设备)
2. 首选System.Timers.Timer
的场景
// 带UI集成的服务组件
public class DataMonitor
{private readonly System.Timers.Timer _timer;private readonly Action _updateUiAction;public DataMonitor(Action updateUi){_updateUiAction = updateUi;_timer = new System.Timers.Timer(1000);_timer.Elapsed += OnTimedEvent;_timer.SynchronizingObject = this; // 同步到UI线程}private void OnTimedEvent(object? sender, ElapsedEventArgs e){// 1. 获取实时数据var data = FetchRealTimeData();// 2. 更新UI(自动切换到UI线程)_updateUiAction(data);}
}
适用场景:
- 需要事件模型的组件库
- 需与UI线程交互的混合应用
- 开发者偏好事件驱动编程
- 定时器生命周期与组件绑定
3. 高精度场景优化技巧
// 首次触发延迟补偿方案
public class HighPrecisionTimer : IDisposable
{private readonly System.Threading.Timer _timer;private volatile bool _firstCall = true;public HighPrecisionTimer(int intervalMs, Action callback){_timer = new System.Threading.Timer(_ =>{if (_firstCall){_firstCall = false;callback(); // 立即补偿首次触发_timer.Change(intervalMs, intervalMs);}else{callback();}}, null, 0, Timeout.Infinite); // 初始只触发一次}public void Dispose() => _timer?.Dispose();
}
五、终极决策树
六、避坑指南
-
资源泄漏预防
// 必须实现IDisposable public class TimerService : IDisposable {private System.Threading.Timer _timer;public void Dispose(){_timer?.Dispose(); // 关键!_timer = null;} }
-
线程安全黄金法则
private int _counter;void TimerCallback(object? state) {// 错误:直接递增// _counter++; // 正确:原子操作Interlocked.Increment(ref _counter); }
-
精度优化实践
- 设置
ThreadPool.SetMinThreads
避免线程池延迟 - 避免在回调中执行阻塞操作
- 使用
Stopwatch
替代DateTime
计时
- 设置
七、总结
System.Timers.Timer
与System.Threading.Timer
的核心差异在于设计哲学而非性能:
- 事件vs委托:
Timers.Timer
提供更高级的事件抽象,Threading.Timer
提供更底层的控制 - 内存开销:
Threading.Timer
零内存分配的特性使其在内存敏感场景完胜 - 精度表现:两种定时器在持续运行后精度差异可忽略(首次触发延迟相同)
终极建议:
- 选择
System.Threading.Timer
当:需要极致性能/低内存开销 - 选择
System.Timers.Timer
当:需要事件模型/与UI线程交互
完整测试代码已上传Github:https://gitcode.com/ben561/NLuaBenchmarkDotNetTest.git
相关文章:

C#定时器深度对比:System.Timers.Timer vs System.Threading.Timer性能实测与选型指南
本文通过真实基准测试揭秘两种常用定时器的性能差异,助你做出最佳选择 一、C#定时器全景概览 在C#生态中,不同定时器适用于不同场景。以下是主流定时器的核心特性对比: 定时器类型命名空间适用场景触发线程精度内存开销依赖框架System.Wind…...
go的select多路复用
传统的方法在遍历管道时,如果不关闭会阻塞而导致 deadlock ,在实际开发中,可能我们不好确定什么关闭该管道。使用select来获取channel里面的数据的时候不需要关闭channel 你也许会写出如下代码使用遍历的方式来实现: for { //…...
深度理解与剖析:前端声明式组件系统
好的,我将根据您的要求,首先进行深度理解与多维思考,然后形成一个全面且有深度的综合性总结,其中包含针对初学者的简洁解释。 1. 核心概念解析:声明式与命令式编程 在深入理解前端的声明式组件系统之前,我…...

解决8080端口被占问题
文章目录 1. 提出问题2. 解决问题2.1 查看占用8080端口的进程2.2 杀死占用8080端口的进程2.3 测试问题是否已解决3. 实战小结1. 提出问题 运行Spring Boot项目,报错8080端口被占 2. 解决问题 2.1 查看占用8080端口的进程 执行命令:netstat -ano | findstr :8080 2.2 杀死占用…...

介绍一种LDPC码译码器
介绍比特翻转译码原理以及LDPC码译码器的设计。 1 译码理论 比特翻转(BF)译码算法是硬判决算法的一种。 主要译码思想是:当有一个校验矩阵出错时,BF 算法认为在这个校验矩阵中一定至少存在一个位置的码字信息是错误的࿱…...

3DMAX+Photoshop教程:将树木和人物添加到户外建筑场景中的方法
在本教程中,我将向您展示如何制作室外场景。我不会详细解释每一个细节,而是想快速概述一下我的方法。 在本教程中,我使用了一个相对简单的3D模型,并向您展示了在一些高质量纹理的帮助下可以做什么。此外,我将向您展示…...
【IOS】【OC】【应用内打印功能的实现】如何在APP内实现打印功能,连接本地打印机,把想要打印的界面打印成图片
【IOS】【OC】【应用内打印功能的实现】如何在APP内实现打印功能,连接本地打印机,打印想打印的界面 设备/引擎:Mac(14.1.1)/cocos 开发工具:Xcode 开发语言:OC/C 开发需求:工程中…...

随记 配置服务器的ssl整个过程
第一步 先了解到这个公钥私钥服务器自己可以生成,但是没什么用,浏览器不会信任的,其他人访问不了。所以要一些中间机构颁布的证书才有用。 一般的服务器直接 安装 Certbot 和插件 //CentOS Nginx 用户: sudo yum install epe…...

数据库高可用架构设计:集群、负载均衡与故障转移实践
关键词:数据库高可用,HA架构,数据库集群,负载均衡,故障转移,SQL Server Always On,MySQL InnoDB Cluster,高可用性组,读写分离,灾难恢复 在当今瞬息万变的数字化时代,数据的价值日益凸显,数据库作为承载核心业务数据的基石,其可用性直接决定了业务的连续性与用户…...
Correlations氛围测试:文本或图像的相似度热图
1 项目概览:Correlations 是什么? Correlations 是一个交互式 UI 工具,Jina AI 开源项目 Correlations 用于调试和可视化文本或图像向量之间的相似性关系,特别适合:快速把相关内容两两对照,比单纯数字报告更直观。Correlations 把这种快速、主观“氛围检视”做成了可视化…...

从0到1:多医院陪诊小程序开发笔记(上)
概要设计 医院陪诊预约小程序:随着移动互联网的普及,越来越多的医院陪诊服务开始向线上转型, 传统的预约方式往往效率低下,用户需耗费大量时间进行电话预约或现场排队,陪诊服务预约小程序集多种服务于一体,可以提高服…...

建立连接后 TCP 请求卡住
大家读完觉得有意义记得关注和点赞!!! 这篇文章描述了一个内核和BPF网络问题 以及故障排除步骤,这是一个值得深入研究的有趣案例 Linux 内核网络复杂性。 目录 1 故障报告 1.1 现象:概率健康检查失败 1.2 范围&am…...
尚硅谷redis7 99 springboot整合redis之连接集群
6381宕机,手动shutdown后在redis中,634自动上位变成master结点。 但是在springboot中却没有动态感知道redisCluster的最新集群消息,所以找不到我们要检索的数据。原因是:SpringBoot 2.X版本,Redis默认的连接池采用 Lettuce&#…...

hive 笔记
1. 查看hive表的文件情况 搭建ui界面机器上查看 show create table xxx;得到文件地址 hdfs查看文件情况 hdfs dfs -ls hdfs://HDFS4005133/usr/hive/warehouse/xxx/xxxx/app_idxxx...

无线通信模块简介
QuecPython 是运行在无线通信模块上的开发框架。对于首次接触物联网开发的用户而言,无线通信模块可能是一个相对陌生的概念。本文主要针对无线通信和蜂窝网络本身,以及模块的概念、特性和开发方式进行简要的介绍。 无线通信和蜂窝网络 物联网对无线通信…...
Go语言之空接口与类型断言
Go 语言中,接口是一种强大的抽象机制。其中,空接口(interface{})和类型断言为我们提供了处理任意类型与类型检查的能力。 一、空接口(interface{}) 空接口是 Go 中最特殊的接口:不包含任何方法…...

把 CURSOR 的工具活动栏改成和 VSCODE 一样的左侧展示
目前使用cursor的时候发现工具栏与vscode的布局不一致,cursor在顶部导致操作起来不方便,如何改成与vscode相同的左侧布局展示。 解决方案 文件→首选项→设置,进入设置中,然后点击这个icon图标,可以打开配置文件 se…...

碰一碰系统源码搭建==saas系统
搭建“碰一碰”系统(通常指基于NFC或蓝牙的短距离交互功能)的源码实现,需结合具体技术栈和功能需求。以下是关键步骤和示例代码: 技术选型 NFC模式:适用于Android/iOS设备的近场通信,需处理NDEF协议。蓝牙…...

不加载PHP OpenTelemetry SDK实现Trace与Logs
目录 前言一、回到OpenTelemetry原理看问题1、数据接收(Receivers)2、数据处理(Processors)3、数据导出(Exporters) 二、不加载OpenTelemetry SDK实现Trace与Logs示例 前言 前面两篇我们分别介绍了OpenT…...

Three.js搭建小米SU7三维汽车实战(6)颜色切换
颜色切换 接下来我们来实现懂车帝的颜色切换效果 可以让ai帮我们生成页面结构以及样式,注意changeCarBodyColor这个函数需要我们自己来写 // 创建颜色选择器UI function createColorSelector() {const colors [{ name: "深海蓝", hex: "#1A9CB0&qu…...

mysql慢sql的实际处理方案之一
复习mysql架构图 当大批量慢sql过来,显然就是占用了线程池的链接,然后长久不释放,所以会出现线程池满的问题,致使正常业务sql也全部阻塞,影响整个业务。 AI搜索如下: 可以考虑一种方案: 将线…...
GitLab 18.0 正式发布,15.0 将不再受技术支持,须升级【六】
GitLab 是一个全球知名的一体化 DevOps 平台,很多人都通过私有化部署 GitLab 来进行源代码托管。极狐GitLab 是 GitLab 在中国的发行版,专门为中国程序员服务。可以一键式部署极狐GitLab。 学习极狐GitLab 的相关资料: 极狐GitLab 官网极狐…...
c/c++的opencv车牌识别
OpenCV 安装: 你需要正确安装 OpenCV 库。Tesseract OCR 安装: 你需要安装 Tesseract OCR 引擎。在 Ubuntu/Debian 上,可以使用:sudo apt-get install tesseract-ocr sudo apt-get install libtesseract-dev sudo apt-get install…...

4.2.3 Spark SQL 手动指定数据源
在本节实战中,我们学习了如何在Spark SQL中手动指定数据源以及如何使用format()和option()方法。通过案例演示,我们读取了不同格式的数据文件,包括CSV、JSON,并从JDBC数据源读取数据,展示了如何将这些数据转换为DataFr…...

【论文解读】CVPR2023 PoseFormerV2:3D人体姿态估计(附论文地址)
论文链接:https://arxiv.org/pdf/2303.17472 源码链接:https://github.com/QitaoZhao/PoseFormerV2 Abstract 本文提出了 PoseFormerV2,通过探索频率域来提高 3D 人体姿态估计的效率和鲁棒性。PoseFormerV2 利用离散余弦变换(DC…...
WPF的交互核心:命令系统(ICommand)
命令系统(ICommand) 1 RelayCommand实现2 CanExecute控制按钮可用性3 参数传递(CommandParameter)3.1 静态参数绑定:3.2 动态参数绑定:3.3 复杂对象参数: 4 异步命令实现5 常见问题排查 WPF的命…...

Maven工程演示
软件:idea 一、项目创建 操作截图file -> New -> Projectnextnext -> Name:工程名称;Location:项目路径;项目创建完成;文件夹基本样例:(如果不完整自己创建即可)MANIFEST.MF内容 二、导入依赖 …...

uniapp分包配置,uniapp设置subPackages
在使用uniapp开发过程中,由于项目比较大,无法直接上传,需要分包后才可以上传。 步骤: 1、在pages同级目录下创建分包的目录(pages_second),把要分包的文件放到该目录下; 2、在pag…...
计算机网络 HTTP篇常见面试题总结
HTTP各版本区别 HTTP 1.0 无状态、无连接:每次请求都需要建立新的 TCP,处理完后立即关闭,导致开销较大。队头阻塞:每个请求必须按照顺序依次处理,前面的请求未完成,后面的请求只能等待,减低了…...

C++八股 —— 手撕线程池
文章目录 一、背景二、线程池实现1. 任务队列和工作线程2. 构造和析构函数3. 添加任务函数4. 完整代码 三、阻塞队列实现1. 基础队列2. 升级版队列 四、测试代码五、相关问题六、其他实现方式 来自:华为C一面:手撕线程池_哔哩哔哩_bilibili 华为海思&am…...