flysun027

有思想的博客
随笔 - 32, 文章 - 0, 评论 - 22, 阅读 - 74182

导航

< 2025年2月 >
26 27 28 29 30 31 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 1
2 3 4 5 6 7 8

在 C# 中使用 Socket.Poll() 提高 CPU 利用率

Posted on   flysun027  阅读(272)  评论(0编辑  收藏  举报

一、背景

        最近在使用 Sharp7.cs 连接西门子 PLC 时,发现当在同一台工控机上连接多个(实际超过100)CPU 时,工控机的 CPU 占用非常大,会去到 20~30%。然而此时实际的网络流量确并不高,只有10mbps。大量 CPU 资源消耗不知道在做什么。因为此时工控机上也没有跑其他业务代码。所以基本可以定位到是 Sharp7.cs 连接 PLC 这里出了问题。那么具体问题发生在哪里呢?只能看源码来发现问题了。

二、原因

        在 Sharp7.cs 中发现了如下代码来读取 PLC 发送过来的数据,通过不断的读取是否有可用字节来判断一次数据是否传输完成。这样写的是可以保证读取要需要长度的数据,很多简单的 socket 编程上都可以见到。由于代码中包含有 Sleep() 并且 sleep 的时间非常短,当同时有大量的线程都在读取数据的时候,大量的 CPU 资源消耗在了线程的切换上,造成 CPU 占用率高,效率严重不足。

复制代码
 1 while ((BytesReaded < Size))
 2 {
 3     Thread.Sleep(2);
 4     SizeAvail = TCPSocket.Available;
 5     try
 6     {
 7         byte[] Flush = new byte[SizeAvail];
 8         int BytesRead = TCPSocket.Receive(Buffer, Start + BytesReaded, SizeAvail, SocketFlags.None);
 9         BytesReaded += BytesRead;
10     }
11     catch { }
12 }
复制代码

三、办法

        C# 提供了 Poll() 方法来改善上述的问题。Poll() 将在指定的时间段内阻塞程序的执行直到 socket 可用。这样 socket 所在线程就会在有可用数据的时候被唤醒, 而不是不停的去测试是否有可读数据了,从而减少线程切换提高 CPU 的利用率。把代码修改如下,(注意 Poll() 方法中的时间单位是微秒)

复制代码
 1 while (BytesReaded < Size && TCPSocket.Poll(1000 * _ReadTimeout, SelectMode.SelectRead))
 2 {
 3     int BytesRead = TCPSocket.Receive(Buffer, Start + BytesReaded, Size - BytesReaded, SocketFlags.None);
 4     if (BytesRead == 0)
 5     {
 6         LastError = S7Consts.errTCPDataReceive;
 7         Close();
 8     }
 9     BytesReaded += BytesRead;
10 }
复制代码

 四、效果

        经过上面的修改,工控机从 PLC 单次读取数据的时间从 16ms 减少到 10ms,极大的提高了 CPU 的利用率。

    完。

如果你觉得这个软件对你有用还可以打赏,打赏用户将会列入打赏榜单。也接受定制服务。

相关博文:
阅读排行:
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
点击右上角即可分享
微信分享提示