Winform Modbus 316线程 异步 λ表达式 泛型与数组 Encoding.ASCII.GetBytes bitConverter 大端小端 寄存器与label

news2026/3/17 16:52:17
this.Invoke首先纠正代码里不是List.Invoke是**this.Invokethis代表当前的FrmMain窗体对象这是WinForm开发中跨线程更新UI的核心方法**灯珠状态、仪表、图表这些UI控件的更新都靠它下面结合代码里的灯珠更新逻辑通俗讲透作用原理写法全程贴合你的代码一、先看代码里的真实写法灯珠更新处的this.Invoke// 后台线程读取灯珠状态bool[] blStatesbool[]blStatesawaitmaster.ReadCoilsAsync(1,0,5);// 跨线程更新UI必须通过this.Invokethis.Invoke(newAction((){// 所有UI更新逻辑都写在这里面灯珠、仪表、图表if(!isWriting){chkState_01.CheckedblStates[0];//1号灯珠chkState_02.CheckedblStates[1];//2号灯珠// ... 3/4/5号灯珠}// 还有仪表、图表的更新逻辑也在这个Invoke里}));二、this.Invoke的核心作用解决「跨线程更新UI的报错问题」1. 先明确WinForm的铁律UI控件只能由**创建它的线程主线程/UI线程**更新其他线程比如Task.Run开的后台数据采集线程直接操作UI控件会报程序异常你的灯珠复选框chkState_01~chkState_05、仪表umTemperature、图表pvTrends都是**主线程UI线程**创建的读取Modbus灯珠状态的逻辑在Task.Run开的后台工作线程里执行如果直接写chkState_01.Checked blStates[0];后台线程直接操作UI程序会立刻抛出**“跨线程操作控件”**的异常直接崩溃。2.this.Invoke就是WinForm提供的跨线程UI更新“桥梁”它的作用是把“更新UI的代码逻辑”从后台线程“委托”给主线程UI线程执行本质是后台线程不直接碰UI只把“要更UI的指令”传给主线程让主线程自己来更完美遵守WinForm的铁律不会报错。三、拆解this.Invoke(new Action(() { ... }))的语法含义通俗版不用抠专业术语这个写法是WinForm跨线程更新UI的固定模板拆开看每一部分都是为了“把UI逻辑传给主线程”new Action(() { ... })把花括号里的UI更新代码打包成一个「可被主线程执行的“指令包”」Action是C#的无返回值委托简单理解就是“一段可执行的代码块”this.Invoke(...)把这个「指令包」提交给主线程UI线程主线程会在空闲时执行包里的UI更新逻辑花括号里的代码所有要更新的UI操作灯珠复选框、仪表数值、图表曲线都必须写在这里面。四、为什么灯珠、仪表、图表的更新都要放在同一个this.Invoke里代码里把灯珠、仪表、湿度/温度/亮度数值、图表曲线的更新全塞在同一个this.Invoke的花括号里核心原因是减少跨线程委托的次数提升程序效率。每次this.Invoke都是后台线程和主线程的一次“通信”如果把灯珠、仪表、图表各写一个this.Invoke会产生3次通信效率低打包在一个里只需要1次通信主线程一次性完成所有UI更新更高效。五、补充和this.Invoke类似的this.BeginInvoke了解即可开发中还有一个this.BeginInvoke和Invoke作用一致都是跨线程更UI区别仅在于this.Invoke同步等待主线程执行完UI更新再继续执行后台线程的后续代码this.BeginInvoke异步不等待把UI指令包传给主线程后后台线程直接继续干活不用等主线程更完UI。你的代码里用this.Invoke是更稳妥的选择避免后台线程数据更新过快导致UI更新错乱。六、极简总结针对你的问题代码里是**this.Invoke**不是List.Invokethis代表当前窗体是跨线程更新UI的核心方法核心作用解决后台数据采集线程直接更新灯珠/仪表/图表等UI控件的报错问题通过“委托主线程更新UI”遵守WinForm的线程规则new Action(() { ... })把灯珠更新等UI逻辑打包成主线程能执行的“代码包”所有UI更新灯珠、仪表、图表都放这里面是为了减少跨线程通信次数提升效率。简单说this.Invoke就是后台线程和UI线程之间的**“UI更新快递员”**后台线程把“要更UI的指令”交给快递员快递员送到主线程主线程自己执行更新全程不违规、不报错。Task.Run你的总结100%精准把两个核心点的作用和区别完全抓透了一句话再帮你定调记死这个核心结论就行Task.Run(async {})是开后台异步线程解决「主线程卡死」this.Invoke是跨线程委托解决「后台线程不能直接更UI」两者是配套使用的黄金组合。再用最简洁的话帮你梳理两者的核心定位配合逻辑更清晰1.Task.Run( async () { ... } )—— 后台异步执行防主线程卡死核心开独立的后台工作线程把「读Modbus硬件、生成模拟数据、计算最值」这些耗时/循环的脏活累活丢进去目的让**主线程UI线程**彻底解放专门管界面渲染、按钮点击等交互杜绝界面卡死关键词异步、后台线程、解耦UI和数据采集。2.this.Invoke( new Action(() { ... }) )—— 跨线程UI更新守WinForm规则核心WinForm铁律「UI控件只能由主线程更新」后台线程不能直接碰UI目的把「更新仪表、灯珠复选框、图表、标签」的UI操作委托给主线程执行既不报错又能实时刷新界面关键词跨线程、UI委托、主线程执行。两者的配套配合逻辑整个系统的核心运行流程Task.Run开后台线程采数据/算数据→ 把最新数据存到temperatureValue等变量 → 调用this.Invoke委托主线程用这些变量更新所有UI控件 → 后台线程延时1秒重复上述流程。简单说这就是WinForm做实时数据监控系统的经典固定写法异步开线程采数据跨线程委托更UI既保证界面丝滑不卡死又能合规、实时地展示数据。chkState_all.Checked !blStates.ToList().Exists(b !b);核心解读一行代码实现「全选/全不选」灯珠的状态联动这行代码是5个灯珠复选框的“全选状态”自动判断逻辑作用是当且仅当所有灯珠都处于开启状态blStates里所有值都是true时chkState_all全选复选框才勾选只要有1个灯珠关闭全选框就取消勾选。先拆解代码的每一部分用通俗的语言讲透结合灯珠场景1. 代码逐段拆解chkState_all.Checked!blStates.ToList().Exists(b!b);代码片段含义灯珠场景blStates从Modbus读取的5个灯珠状态数组bool[5]blStates[0]1号灯、…blStates[4]5号灯true开、false关.ToList()把数组转成List只为调用Exists方法数组本身没有ExistsList有.Exists(b !b)检查List中是否存在满足条件的元素b !b “元素的值是false灯珠关闭”→ 结果true有灯珠关false所有灯珠开!最前面的取反对Exists的结果取反如果Exists返回true有灯关→ 取反后false全选框不勾如果Exists返回false全灯开→ 取反后true全选框勾chkState_all.Checked 把最终结果赋值给全选复选框的勾选状态2. 举2个实际例子一看就懂例子1所有灯珠都开blStates [true,true,true,true,true]blStates.ToList().Exists(b !b)→ 检查是否有false→ 结果false取反后 →truechkState_all.Checked true→ 全选框勾选。例子23号灯珠关闭blStates [true,true,false,true,true]blStates.ToList().Exists(b !b)→ 检查是否有false→ 结果true取反后 →falsechkState_all.Checked false→ 全选框取消勾选。3. 简化理解等价的“人话代码”这行代码完全等价于下面的写法新手更易读只是原代码用LINQ简化成了一行// 遍历所有灯珠状态判断是否全部为trueboolisAllOntrue;foreach(boollightStateinblStates){if(lightStatefalse)// 只要有一个灯关{isAllOnfalse;break;// 不用继续遍历了}}// 给全选框赋值chkState_all.CheckedisAllOn;4. 核心设计目的这是WinForm里**“批量控件全选控件”的经典联动逻辑**从硬件读取5个灯珠的实时状态后自动同步“全选框”的勾选状态用户看全选框就能快速判断“是否所有灯珠都开启”不用逐个看5个灯珠复选框提升界面易用性。总结核心功能根据5个灯珠的实时状态自动更新“全选复选框”的勾选状态逻辑本质判断blStates数组中是否“全为true”是则勾选全选框否则取消写法特点用LINQ的Exists方法简化了遍历判断一行代码搞定是C#中简洁高效的写法最终目的提升界面易用性让用户快速感知所有灯珠的整体状态。简单说这行代码就是“全选框跟着所有灯珠的状态自动走”的核心逻辑是界面交互设计中很常见的优化写法。List 与 byte[]你的理解抓到了核心先给你结论✅ 用Listbyte核心就是利用它动态扩容的特性解决字符串转字节后奇数长度补0的问题✅ 不是不能直接用Listbyte接而是Encoding.ASCII.GetBytes(sendText)本身只能返回固定长度的数组必须先转成数组再丢进List这是方法返回值的限制而非List的使用限制。下面基于你真实的GetUshortData代码逐行讲透每一步的原因没有一句脑补先贴你代码里的真实方法privateushort[]GetUshortData(stringsendText){ListbytebyteListnewListbyte();byte[]textBytesEncoding.ASCII.GetBytes(sendText);//将文本转换为字节数组byteList.AddRange(textBytes);//ushort 1个ushort2字节if(textBytes.Length%21){byteList.Add(0x00);}ListushortushortListnewListushort();for(inti0;ibyteList.Count;i2){byte[]itemnewbyte[2];item[0]byteList[i1];item[1]byteList[i];ushortList.Add(BitConverter.ToUInt16(item,0));}returnushortList.ToArray();}逐问解答为什么要定义2个byte相关容器为什么不能直接用List接问题1为什么先定义byte[] textBytes再用byteList.AddRange(textBytes)而不是直接用List接sendText核心原因Encoding.ASCII.GetBytes(string)这个方法的返回值类型是固定的byte[]它没有提供直接返回Listbyte的重载方法你想把字符串转成ASCII字节只能先得到固定长度的byte数组再通过AddRange把数组里的所有字节添加到Listbyte中这是C#类库的方法设计限制不是List的问题List本身可以接收任意字节但转ASCII的方法只给数组必须做这一步转换。问题2为什么一定要再包一层Listbyte byteList核心就是你说的动态扩容这个方法的最终目的是把字节转成ushort[]而1个ushort必须占2个字节Modbus协议要求写入保持寄存器的ushort是16位2字节所以必须保证字节总数是偶数如果sendText转成字节后是奇数长度比如3个字节直接转ushort会少1个字节程序报错Listbyte的动态Add方法可以轻松实现补0操作byteList.Add(0x00)而如果直接用byte[]固定长度补0需要重新创建新数组、复制旧数据代码会非常繁琐。问题3如果不用List直接用byte[]会怎么样给你写对比代码看差距如果硬要用固定数组实现代码会变成这样繁琐且易出错// 不用List的糟糕写法对比你的代码privateushort[]GetUshortData_Bad(stringsendText){byte[]textBytesEncoding.ASCII.GetBytes(sendText);// 第一步计算新长度奇数补1intnewLentextBytes.Length%20?textBytes.Length:textBytes.Length1;// 第二步创建新数组复制旧数据byte[]tempBytesnewbyte[newLen];Array.Copy(textBytes,tempBytes,textBytes.Length);// 第三步奇数的话最后一位补0数组默认0可省略但逻辑要写清if(textBytes.Length%21)tempBytes[newLen-1]0x00;// 后续转ushort逻辑不变...ListushortushortListnewListushort();for(inti0;itempBytes.Length;i2){byte[]itemnewbyte[2];item[0]tempBytes[i1];item[1]tempBytes[i];ushortList.Add(BitConverter.ToUInt16(item,0));}returnushortList.ToArray();}对比你的代码用List少了计算新长度、创建新数组、数组复制三步代码简洁至少50%这就是Listbyte动态扩容的核心价值再解答你隐含的疑问循环里的byte[] itemnew byte[2]是干嘛的这不是多余的是Modbus协议的字节序要求大端序和List无关顺带讲透BitConverter.ToUInt16在Windows系统中默认是小端序低字节在前高字节在后而Modbus RTU协议要求大端序高字节在前低字节在后所以要创建2字节的临时数组把byteList[i1]高字节放item[0]byteList[i]低字节放item[1]实现字节序反转保证Modbus设备能正确解析数据。核心总结完全基于你的代码问题定义2个byte相关容器byte[]Listbyte不是多余的byte[] textBytes因为Encoding.ASCII.GetBytes只能返回固定数组是方法限制Listbyte byteList利用动态扩容轻松实现奇数长度补0避免固定数组的繁琐操作你的理解完全正确泛型List的动态更新长度是这一步的核心原因不是不能直接用List接sendText而是转ASCII的方法不支持直接返回List必须先转数组再入List。简单说这一步的写法是C#类库限制Modbus协议要求下的最优解既解决了字节补0的问题又让代码最简洁。bitConverter先给你核心结论直击问题BitConverter.ToUInt16是C#内置静态方法作用就是把字节Byte数组转成16位无符号整数ushort即UInt16你的理解完全正确Byte ≠ Bit1个Byte字节 8个Bit比特/位代码里操作的是字节数组不是比特没有ByteConverter因为BitConverter是C#官方命名它的核心是按“二进制位Bit”解析字节Byte覆盖所有基础类型的字节转值无需单独做ByteConverter。逐问讲透全程贴合你的代码场景问题1BitConverter.ToUInt16到底转的是Byte还是Bit转的是Byte数组方法名带Bit是因为底层按二进制位解析你的代码里BitConverter.ToUInt16(item,0);入参item是2个Byte的数组16个Bit刚好对应1个UInt16方法底层会把这2个Byte的16个二进制位按顺序拼接转换成对应的UInt16数值命名为BitConverter是因为它的核心是操作二进制位而不是直接操作ByteByte只是承载二进制位的容器。问题2Byte和Bit的核心区别代码里用的是Byte别搞混名称缩写大小代码里的类型/使用比特Bit1个二进制位底层解析代码不直接操作字节Byte8个Bit代码里的byte[]/ListbyteModbus通信的基本单位✅ 你的代码里全程操作的是Byte字符串转byte[]、Listbyte补0、item是byte[]Modbus RTU协议的通信单位也是字节Bit只是底层最小单位。问题3为什么C#没有ByteConverter只有BitConverter因为BitConverter是通用型工具类覆盖了所有基础类型的「字节数组↔数值」转换功能远大于单独的ByteConverter官方没必要重复造轮子// BitConverter支持所有基础类型你的代码只用了ToUInt16BitConverter.ToUInt16(byte[]value,intstartIndex);// 字节转UInt16/ushortBitConverter.ToInt32(byte[]value,intstartIndex);// 字节转Int32/intBitConverter.ToDouble(byte[]value,intstartIndex);// 字节转Double/doubleBitConverter.GetBytes(intvalue);// 数值转字节数组反向// ... 还有bool/long/float等所有类型如果做ByteConverter只能处理字节相关转换功能单一而BitConverter以二进制位为核心能处理所有基于字节的类型转换是更通用的设计。问题4结合你的代码再看BitConverter.ToUInt16的实际作用你的代码里item是2个Byte的大端序数组调用该方法后方法读取item[0]和item[1]的16个二进制位按Windows小端序规则拼接成二进制数转换成对应的十进制ushort数值最终存入ushortList传给Modbus的WriteMultipleRegistersAsync方法要求入参是ushort[]。极简总结记死这3点就够BitConverter.ToUInt16是C#内置方法把2个Byte的数组转成UInt16/ushort你的代码里用它完全匹配Modbus的参数要求Byte≠Bit1Byte8Bit代码里/Modbus里操作的都是ByteBit是底层解析单位无ByteConverter因为BitConverter是通用型字节转值工具覆盖所有基础类型官方统一命名和设计无需单独的字节转换器。简单说BitConverter是“大而全”的工具你的代码只是用了它其中一个功能Byte转UInt16这也是C#官方的标准设计思路~大小端你的总结100%精准大端序的核心就是高字节在前低字节在后存/传的时候高位字节放数组/协议帧的低索引位低位字节放高索引位。结合你代码里的item数组再强化下更贴合你的实际使用场景byte[]itemnewbyte[2];item[0]byteList[i1];// 高字节 → 放数组【第0位前】item[1]byteList[i];// 低字节 → 放数组【第1位后】这行代码就是纯纯的大端序实现完全匹配Modbus RTU协议的字节序要求。补充个小对比帮你记死大端序Modbus用高字节→数组0位低字节→数组1位高前低后小端序Windows默认低字节→数组0位高字节→数组1位低前高后你这一句就抓到了大端序的本质完全不用再记复杂概念了你的理解是对的加0x00就是在byteList末尾追加一个值为0的字节不会报错反而这步是必须的容错处理核心是为了适配ushort双字节的转换要求我结合你的代码把这步的逻辑、作用、为什么加0x00讲透byteList.Add(0x00)1. 先明确byteList.Add(0x00);到底做了什么0x00是十六进制表示的0字节和十进制的0、字节型的(byte)0完全等价这行代码就是当sendText转成的字节数是奇数时在byteList的最后追加一个值为0的空字节让整个字节列表的长度变成偶数。它是纯纯的补位操作不会修改原有字节也不会触发任何报错是安全的容错处理。2. 为什么必须加这个0x00核心原因ushort是2字节固定长度你的最终目标是把字节转成ushort[]传给Modbus而1个ushortUInt16必须由2个字节组成这是C#的类型规定也是Modbus协议的要求如果字节数是偶数2/4/6…可以刚好分成N组2字节完美转成N个ushort无需补位如果字节数是奇数1/3/5…最后会剩1个孤立字节无法组成ushort直接转换会索引越界报错举个你的代码场景的例子场景1发送字符串AB→转ASCII字节[0x41,0x42]2个偶数→不用补0直接转1个ushort场景2发送字符串A→转ASCII字节[0x41]1个奇数→必须补0变成[0x41,0x00]2个偶数才能转1个ushort否则循环i2时会超出数组长度程序崩溃。3. 为什么补的是0x00而不是其他数字补0x00空字节是工业通信的通用标准原因有2个不影响原始数据0字节是“无意义补位”Modbus设备解析时会识别出这是补的空字节不会把它当成有效数据能正确还原原始的字符串ASCII编码的兼容性ASCII编码中0x00是空字符NUL不属于任何可打印字符不会和原始字符串的ASCII字节冲突是最安全的补位值。4. 结合你的代码看补0的完整逻辑byte[]textBytesEncoding.ASCII.GetBytes(sendText);byteList.AddRange(textBytes);// 仅当字节数为奇数时补0x00让长度变偶数if(textBytes.Length%21){byteList.Add(0x00);// 追加0字节无报错纯补位}// 后续循环i2按2字节一组转ushort永远不会越界核心总结一句话讲透byteList.Add(0x00);不会报错反而能避免报错它是在字节数为奇数时追加一个0值字节做补位让字节总数变成偶数保证后续能按“2字节一组”顺利转成ushort是适配C#类型和Modbus协议的必要容错步骤补的0x00就是十六进制的0字节是工业通信中最安全的补位值。反向验证如果注释掉这行代码会怎样你可以试一下当发送奇数长度的字符串如A/123时程序会直接抛出**IndexOutOfRangeException索引越界异常因为循环到最后会只剩1个字节无法取到i1的位置这就是这行补0代码的核心价值。你的疑问特别关键核心是「界面只显示1个Label但数据在Modbus侧是按「寄存器」拆分存储的所以会占用多个寄存器」和Label数量无关只和你发送的字符串转成的ushort[]长度有关**我基于你的代码Modbus规则讲透一看就懂寄存器 与label先定核心规则Modbus侧的硬性要求和界面无关Modbus的保持寄存器是**16位2字节**为1个单位1个ushort刚好对应1个寄存器——你代码里把字符串转成了ushort[]数组数组有多少个元素就会占用Modbus多少个寄存器这就是“写多个寄存器”的原因。结合你的代码拆解「1个Label显示 → 多个寄存器存储」的逻辑步骤1界面侧——1个Label只负责「最终显示字符串」不管底层存储你界面上的lblShowMsg.Text sendText;只是把原始字符串展示出来它是“结果呈现”只认字符串不管这个字符串在Modbus侧被拆成了多少份所以看起来只是“1个内容”。步骤2Modbus侧——字符串必须拆成ushort[]自然占用多个寄存器你的GetUshortData方法会把字符串转成ushort[]数组长度由字符串的字节数决定补0后偶数字节2字节1个ushort举3个实际例子最直观你输入的字符串转ASCII字节数补0后字节数转成ushort[]长度占用Modbus寄存器数量写入的寄存器地址起始8“A”1211个8号“AB”2211个8号“ABC”3422个8号、9号“ABCD”4422个8号、9号✅ 结论不是Label多是字符串转成的ushort[]有多个元素所以必须写「多个」寄存器哪怕只占1个寄存器代码也用WriteMultipleRegistersAsync写多寄存器方法因为这个方法兼容「1个/多个」寄存器写入不用单独区分是开发的便捷写法。再解答为什么不用「写单寄存器方法」非要用「写多寄存器方法」你代码里用WriteMultipleRegistersAsync功能码0x10而不用WriteSingleRegisterAsync功能码0x06核心是兼容性写单寄存器方法只能写1个ushort1个寄存器如果字符串转成的ushort[]长度1比如ABC转成2个ushort就会报错无法发送写多寄存器方法兼容1个/多个ushort写入不管字符串多长转成的ushort[]有多少元素都能一次性写入对应的寄存器不用写判断逻辑代码更简洁。简单说用写多寄存器方法一个方法适配所有字符串长度的发送场景不用区分“1个寄存器”还是“多个寄存器”。最后梳理完整逻辑界面1个Label ↔ Modbus多个寄存器你在txtSendMsg输入任意字符串 → 界面只展示1个输入框、1个显示Label代码把字符串转成byte[]→补0成偶数字节→转成ushort[]N个元素调用写多寄存器方法把N个ushort一次性写入Modbus从8号开始的N个寄存器Modbus设备接收后从对应寄存器中读取所有ushort→反向解析成byte[]→转成原始字符串你界面的lblShowMsg直接显示原始字符串完全不用管Modbus侧拆成了多少寄存器。极简总结Label数量≠寄存器数量Label只是界面的“结果展示”只认字符串寄存器是Modbus的“数据存储单位”按2字节/个拆分数据和界面无关写多寄存器的原因字符串转成的ushort[]可能有多个元素1个ushort对应1个寄存器自然会占用多个寄存器代码用写多寄存器方法是为了兼容不管字符串多长都能一次性写入不用区分单/多寄存器代码更简洁。简单说界面看的是“整体的字符串”Modbus看的是“拆分后的ushort数据块”这就是为什么界面只有1个Label却要写多个寄存器的核心原因

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2420045.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;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…