.NET工控概念科普——工控的"实时"和Web的"实时"不是一回事
前言
大家好,我是wacky。上四篇我们画完了.NET工控的生态地图——通信协议、数据存储、业务逻辑、界面展示,一条完整的技术栈链路。从这一篇开始,我们换个角度:不聊技术栈,聊聊一些工控的基本概念。这些概念看起来"虚",但它们直接决定你做架构决策时的判断力。
第一个要聊的概念是"实时"。如果你做过Web开发,你对"实时"的理解大概是WebSocket推送、SignalR长连接、消息队列的毫秒级延迟。但在工控领域,"实时"这个词的含义完全不同——它不是"快",而是"确定"。
Web的"实时":够快就行
先明确一下Web开发中"实时"是什么意思。你给一个Web系统发请求,服务器处理完返回结果,整个过程从几毫秒到几百毫秒不等。在用户体验层面,"实时"通常意味着"感觉不到延迟"——比如聊天消息秒推、股票行情毫秒刷新、在线协作光标跟随。技术上靠的是WebSocket、长轮询这些方案。
这种"实时"的核心特征是:快,但不保证。网络抖动一下,延迟可能从50ms跳到500ms;服务器GC一下,响应可能卡半秒。用户顶多觉得"刚才卡了一下",刷新就好了。因为Web系统的业务逻辑不依赖精确的时间——你晚0.5秒收到聊天消息,不影响任何事。
工控的"实时":必须确定
工控的"实时"不是"快",是"确定"。这不是文字游戏——"快"是平均值,"确定"是最坏情况。
举个例子。一个化工厂的反应釜,温度超过120℃必须立刻关闭加热器。从温度传感器读到120℃,到PLC输出"关闭加热器"信号,这个过程必须在确定的、可预见的时间内完成。这个时间不是"大概50ms",而是"严格不超过5ms"。
为什么"大概"不行?因为如果你的系统"大部分时候3ms完成,偶尔50ms",那偶尔的50ms发生在温度超标的那一刻,反应釜可能已经到150℃了——轻则废料,重则爆炸。
这就是工控"实时"的核心:确定性响应时间(Deterministic Response Time)。不是平均多快,而是最坏多慢。工控系统设计的时候,关注的是"这个操作最长需要多长时间"——因为最坏情况才是安全边界。
硬实时 vs 软实时
理解了"确定"这个概念,再来看工业领域对实时的分类:
硬实时(Hard Real-Time):错过截止时间意味着系统故障。上面那个反应釜的例子就是硬实时——超过5ms没响应,后果是安全事故或设备损坏。硬实时的典型场景是运动控制(伺服电机位置环在微秒级)、安全联锁(急停回路必须在几毫秒内切断)、高速数据采集。
软实时(Soft Real-Time):错过截止时间会导致性能下降但不造成事故。比如上位机界面上温度曲线的刷新——本来应该每100ms刷新一次,偶尔200ms刷新一次,操作员觉得"有点卡",但不影响安全。软实时的典型场景是HMI界面刷新、历史数据记录、报警日志。
这中间还有一个"固实时(Firm Real-Time)"的概念——错过截止时间不会造成安全事故,但数据就无效了。比如高速采集卡丢失了一个采样点,这个点永远回不来了,但不影响系统安全。
为什么PLC能做硬实时,.NET不能
聊到这里,你可能想问:.NET能做硬实时吗?
答案是:不能。不是.NET不够好,是设计目标不同。
PLC能做硬实时,因为它的运行机制是为实时控制设计的。PLC的工作方式是"扫描循环"——输入采样→程序执行→输出刷新→回到输入采样。每次扫描的时间是确定的,因为PLC不跑操作系统,没有多任务调度、没有GC、没有网络中断。它的处理器就干一件事:按固定周期跑你的控制逻辑。扫描周期可以精确到毫秒甚至微秒级,而且每次扫描的时间高度一致。
.NET运行在通用操作系统上(Windows/Linux),操作系统有几百个进程在跑、有内存管理、有磁盘IO、有网络中断。即使你把.NET程序的优先级调最高,操作系统仍然可能在你最关键的时刻做一次内存页交换,让你的代码卡住几十毫秒。这几十毫秒对Web系统无所谓,对硬实时控制就是灾难。
所以工业控制中硬实时场景的架构是:PLC做硬实时控制,上位机(.NET)做软实时——数据采集、界面展示、报警处理、历史记录。上位机不参与毫秒级的控制决策,它通过通信协议(Modbus/OPC UA)读取PLC已经处理好的数据,展示给人看、存储到数据库、做趋势分析。
这个分工意味着:.NET上位机的"实时"目标是"及时",不是"确定"。你需要在100ms内把温度显示到界面上,但偶尔200ms也可以接受。
上位机开发的"实时"技巧
虽然.NET做不了硬实时,但上位机开发中仍然有一些"实时"相关的坑需要注意。这里说两个最关键的。
第一个是轮询频率。很多工控新手上来就写一个100ms的定时器不停地读PLC数据。但如果PLC的扫描周期是20ms,你100ms读一次没问题。但如果PLC的扫描周期是200ms,你100ms读一次,读到的数据有一半是重复的——PLC还没更新呢。轮询频率要匹配PLC的扫描周期,不是越快越好。通常建议轮询周期≥2倍PLC扫描周期。
第二个是UI线程不能阻塞。工控上位机的界面卡顿,80%的原因不是"电脑太慢",是有人把耗时操作放在了UI线程上。WPF的数据绑定机制已经帮你解决了大部分问题——数据更新在后台线程完成,ViewModel通过INotifyPropertyChanged通知界面刷新。但如果你在按钮点击事件里写了一个同步的PLC通信操作,界面就会卡住。记住一条铁律:所有通信操作必须异步。
// 错误:按钮事件里同步读PLC,界面卡死 private void ReadButton_Click(object sender, RoutedEventArgs e) { var data = plc.ReadHoldingRegisters(0, 10); // 同步阻塞UI线程 // 空值和长度检查 if (data == null || data.Length == 0) { TemperatureText.Text = "无数据"; return; } TemperatureText.Text = data[0].ToString(); } // 正确:异步读PLC,界面不卡 private async void ReadButton_Click(object sender, RoutedEventArgs e) { // 防止重入:读取过程中禁用按钮 ReadButton.IsEnabled = false; try { // 在后台线程读取 PLC,不阻塞 UI var data = await Task.Run(() => plc.ReadHoldingRegisters(0, 10)); // 空值和长度检查 if (data == null || data.Length == 0) { TemperatureText.Text = "无数据"; return; } // await 之后自动回到 UI 线程,可以安全更新控件 TemperatureText.Text = data[0].ToString(); } catch (Exception ex) { // async void 中必须捕获所有异常,否则直接崩溃 TemperatureText.Text = $"读取失败: {ex.Message}"; } finally { ReadButton.IsEnabled = true; } }
后记
"实时"这个词在IT和OT两个世界里含义完全不同。做Web的人聊实时,说的是体验;做工控的人聊实时,说的是安全。理解了这个区别,你就理解了为什么工控系统的架构是PLC+上位机的组合,而不是一个.NET程序包办一切。
下一篇我们聊PLC的扫描周期——理解了它,才算真正入了工控的门。诸君共勉。
本文首发于我的公众号【wacky的碎碎念】,欢迎关注追更!

原文地址: https://www.cveoy.top/t/topic/qHhy 著作权归作者所有。请勿转载和采集!