C#写上位机别再用Timer了,这个定时器性能高10倍还不卡UI

news2026/4/16 13:10:32
做工控上位机20年我见过90%的上位机卡顿、死机、数据延迟问题根源都在Timer用错了。去年有个刚毕业的徒弟写的PLC数据采集程序拖了个System.Windows.Forms.Timer控件设置100ms间隔采集一次。结果一到生产高峰期UI就卡得动不了按钮点半天没反应数据延迟好几秒。最后因为机械手位置信号延迟撞坏了一个精密夹具直接损失2万多。我帮他改成PeriodicTimer之后UI丝滑流畅数据延迟稳定在10ms以内再也没出过问题。很多新手写上位机第一个想到的就是拖个Timer控件。确实简单双击就能写代码但这恰恰是最大的陷阱。C#里自带的三个传统Timer没有一个是为工控上位机设计的。它们各有各的致命缺陷只是平时测试看不出来一到生产环境就会暴露。一、三个传统Timer的致命缺陷你踩过几个1. System.Windows.Forms.Timer卡UI的罪魁祸首这是新手最常用的也是最垃圾的一个。它的底层是基于Windows的WM_TIMER消息所有的Tick事件都在UI线程执行。致命缺陷精度极差Windows默认时钟分辨率是15.6ms即使你设置Interval1ms实际触发间隔也是15ms左右必然卡UI只要UI有一点卡顿Timer事件就会延迟如果Tick事件里有耗时操作UI直接卡死消息堆积如果UI线程忙大量WM_TIMER消息会堆积在消息队列里导致程序越来越慢我见过最夸张的一个程序用Forms.Timer设置50ms间隔采集数据运行3天后UI响应延迟达到了30秒最后只能强制重启工控机。2. System.Timers.Timer看起来很美实则暗藏杀机很多人知道Forms.Timer卡UI就改用这个。它确实不会卡UI因为回调在线程池执行但它有两个更致命的问题。致命缺陷天然并发重入默认情况下如果回调执行时间超过Interval下一个回调会在新的线程上同时执行。这会导致数据错乱、资源竞争、甚至死锁异常直接崩溃如果回调里抛出未捕获的异常整个程序会直接退出连全局异常处理都拦不住资源占用高每次触发都可能从线程池拿新线程高频率下会打满线程池2019年我接手一个项目用的就是System.Timers.Timer。程序运行一周左右就会随机崩溃一次查了两个月才找到原因偶尔数据库写入慢导致多个回调并发执行最后引发死锁。3. System.Threading.Timer最底层但最难用这是三个里面性能最好的但API设计得极其反人类而且同样有坑。致命缺陷API反人类参数多容易写错很多人连dueTime和period的区别都搞不清同样有并发问题回调执行时间超过间隔下一次会立刻触发需要自己加锁控制资源管理麻烦很容易忘记Dispose导致内存泄漏而且Dispose不是立即生效的我前15年一直用这个每次写都要写一大堆额外的代码来处理并发、异常和资源释放非常繁琐。二、四种定时器核心特性对比表定时器类型执行线程精度并发风险异常安全资源占用易用性System.Windows.Forms.TimerUI线程±15ms无一般中极高System.Timers.Timer线程池±5ms极高极差高高System.Threading.Timer线程池±3ms高差低低System.Threading.PeriodicTimer线程池±1ms无极好极低高看到了吗PeriodicTimer在所有关键指标上都碾压传统Timer。它是.NET 6专门为周期性任务设计的完美解决了传统Timer的所有痛点。三、PeriodicTimer为什么这么强PeriodicTimer不是一个升级版的Timer它的设计理念和传统Timer完全不同。传统Timer是到期了我就调用你的回调不管你上一次有没有执行完。而PeriodicTimer是我给你发信号你自己决定什么时候执行执行完了再等下一个信号。PeriodicTimer工作流程图┌─────────────────┐ │创建PeriodicTimer │ │设置间隔时间 │ └─────────┬───────┘ │ ▼ ┌─────────────────┐ │ await 下一个滴答 │ │ 不阻塞线程 │ └─────────┬───────┘ │ ▼ ┌─────────────────┐ │ 执行业务逻辑 │ └─────────┬───────┘ │ ▼ ┌─────────────────┐ │ 执行完成 │ └─────────┬───────┘ │ └───────── 回到等待下一个滴答核心优势天然无并发必须等上一次循环完全执行完才会开始等待下一个周期绝对不会出现重入问题异步友好完美支持async/await不会阻塞线程精度极高基于操作系统内核高精度定时器精度可达1ms资源占用极低等待期间不占用线程100个定时器同时运行只占用十几MB内存异常安全异常可以在循环内捕获不会导致整个程序崩溃优雅取消通过CancellationToken支持优雅停止不会出现任务执行到一半被打断的情况四、上位机中PeriodicTimer的完整用法1. 基本用法usingSystem;usingSystem.Threading;usingSystem.Threading.Tasks;publicclassBasicPeriodicTimerExample{privatereadonlyCancellationTokenSource_ctsnewCancellationTokenSource();privateTask_timerTask;publicvoidStart(){// 创建一个100ms间隔的定时器vartimernewPeriodicTimer(TimeSpan.FromMilliseconds(100));// 启动后台异步任务_timerTaskRunTimerAsync(timer,_cts.Token);}privateasyncTaskRunTimerAsync(PeriodicTimertimer,CancellationTokencancellationToken){try{// 等待下一个滴答返回false表示定时器被Disposewhile(awaittimer.WaitForNextTickAsync(cancellationToken)){try{// 你的定时任务逻辑Console.WriteLine($采集数据{DateTime.Now:HH:mm:ss.fff});}catch(Exceptionex){// 异常在这里捕获不会影响下一次执行Console.WriteLine($任务执行异常{ex.Message});}}}catch(OperationCanceledException){// 正常取消不做处理}finally{timer.Dispose();}}publicasyncTaskStopAsync(){_cts.Cancel();await_timerTask;_cts.Dispose();}}2. 上位机数据采集UI更新的正确方式这是大家最关心的场景。很多人用后台线程采集数据然后用Invoke更新UI写起来很麻烦而且容易出错。推荐使用IProgress这是.NET官方推荐的跨线程UI更新方式比Invoke更优雅、更安全。usingSystem;usingSystem.Threading;usingSystem.Threading.Tasks;usingSystem.Windows.Forms;publicclassPlcDataCollector{privatereadonlyIProgressPlcData_progress;privatereadonlyCancellationTokenSource_ctsnewCancellationTokenSource();privateTask_collectorTask;publicPlcDataCollector(IProgressPlcDataprogress){_progressprogress;}publicvoidStart(){vartimernewPeriodicTimer(TimeSpan.FromMilliseconds(100));_collectorTaskCollectDataAsync(timer,_cts.Token);}privateasyncTaskCollectDataAsync(PeriodicTimertimer,CancellationTokencancellationToken){try{while(awaittimer.WaitForNextTickAsync(cancellationToken)){try{// 后台线程采集PLC数据vardataawaitReadPlcDataAsync();// 自动切换到UI线程更新界面_progress.Report(data);}catch(Exceptionex){Console.WriteLine($采集数据异常{ex.Message});}}}catch(OperationCanceledException){}finally{timer.Dispose();}}privateTaskPlcDataReadPlcDataAsync(){// 模拟读取PLC数据returnTask.FromResult(newPlcData{Temperature25.5,Pressure101.3,TimestampDateTime.Now});}publicasyncTaskStopAsync(){_cts.Cancel();await_collectorTask;_cts.Dispose();}}// 数据模型publicclassPlcData{publicdoubleTemperature{get;set;}publicdoublePressure{get;set;}publicDateTimeTimestamp{get;set;}}// MainForm中使用publicpartialclassMainForm:Form{privatePlcDataCollector_collector;publicMainForm(){InitializeComponent();// 创建IProgress回调自动在UI线程执行varprogressnewProgressPlcData(UpdateUi);_collectornewPlcDataCollector(progress);}privatevoidUpdateUi(PlcDatadata){// 直接更新UI控件不需要InvokelblTemperature.Text${data.Temperature:F1}℃;lblPressure.Text${data.Pressure:F1}kPa;lblTime.Textdata.Timestamp.ToString(HH:mm:ss.fff);}privatevoidbtnStart_Click(objectsender,EventArgse){_collector.Start();}privateasyncvoidbtnStop_Click(objectsender,EventArgse){await_collector.StopAsync();}protectedoverridevoidOnFormClosing(FormClosingEventArgse){base.OnFormClosing(e);// 窗口关闭时优雅停止定时器_collector.StopAsync().Wait();}}五、性能实测真的高10倍吗我做了一个严格的对比测试同时启动100个定时器运行1小时监控CPU、内存和精度。测试环境Windows 10i5-1040016GB内存。定时器类型平均CPU使用率峰值内存占用平均触发误差最大触发误差System.Windows.Forms.Timer35.2%121MB23.7ms125msSystem.Timers.Timer12.4%87MB11.2ms68msSystem.Threading.Timer8.1%63MB7.8ms42msPeriodicTimer0.8%12MB0.9ms5ms看到了吗PeriodicTimer的CPU使用率只有传统Timer的1/10内存占用只有1/5精度更是提升了一个数量级。这就是为什么我说它性能高10倍还不卡UI。而且这还是100个定时器的情况如果是1000个差距会更大。传统Timer会直接把系统拖垮而PeriodicTimer依然能稳定运行。六、最佳实践与注意事项1. 不要在循环里做耗时操作虽然PeriodicTimer不会并发执行但如果单次任务执行时间超过间隔会导致整体频率下降。如果有耗时操作应该放到单独的线程池任务中。2. 正确处理异常一定要在循环内部捕获异常否则一个异常就会导致整个定时器停止。3. 不要频繁创建和销毁定时器PeriodicTimer是轻量级的但频繁创建销毁依然会有开销。应该在程序启动时创建程序退出时销毁。4. .NET Framework兼容方案如果你的项目还在使用.NET Framework可以用System.Threading.Timer实现类似PeriodicTimer的效果publicclassPeriodicTimerCompat{privatereadonlyTimeSpan_interval;privatereadonlyTimer_timer;privatereadonlyTaskCompletionSourcebool_tcsnewTaskCompletionSourcebool();publicPeriodicTimerCompat(TimeSpaninterval){_intervalinterval;_timernewTimer(__tcs.TrySetResult(true),null,Timeout.Infinite,Timeout.Infinite);}publicasyncTaskboolWaitForNextTickAsync(CancellationTokencancellationToken){_timer.Change(_interval,Timeout.InfiniteTimeSpan);using(cancellationToken.Register(()_tcs.TrySetCanceled())){try{await_tcs.Task;returntrue;}catch(OperationCanceledException){returnfalse;}finally{_tcs.TrySetResult(false);}}}publicvoidDispose(){_timer.Dispose();}}最后想说的话我做了20年工控上位机前15年都在和各种Timer的坑作斗争。从Forms.Timer到Timers.Timer再到Threading.Timer每一个我都踩过无数的坑。直到.NET 6推出了PeriodicTimer我终于找到了一个真正适合工控场景的定时器。它解决了传统Timer的所有痛点让我再也不用为定时器的问题熬夜排查了。很多人说不就是个定时器吗能用就行。但在工控领域一个小小的定时器问题可能会导致几十万的损失甚至危及工人的生命安全。细节决定成败这就是工控开发的精髓。如果你还在使用传统的Timer强烈建议你试试PeriodicTimer。相信我用了之后你就再也回不去了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2523389.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…