C# 占用CPU的问题

.Net技术 码拜 9年前 (2015-05-11) 2337次浏览 0个评论

使用C#写了一个串口通信界面,使用的是队列的方式来处理数据,即将接收数据、数据解析分开,首先使用C#自带的serialPort_DataReceived函数接收数据,然后将接收到的数据加入到队列中。在载入界面时会打开数据解析线程,当队列中有数据时,数据解析线程会解析数据。遇到的问题是,查看任务管理器发现我的应用程序的cpu占用率达到了25,当我把解析线程注释掉后应用程序的cpu暂用率变为0,这就是解析线程太耗cpu,如图所示。要是最近几年的电脑还不会出现卡顿的现象,但是如果是比较旧的电脑就会出现卡顿的现象了,请问有什么好的方法优化?解析线程源代码如下:
C#  占用CPU的问题
C#  占用CPU的问题

DataDealThread = new Thread(DataDealMethod);
 DataDealThread.Start();

private void DataDealMethod()
        {
            while (true)
            {
                string strRcv = null;
                try
                {
                    if (RcvQueue.Count >= 1)
                    {
                        byte[] ReceiveDataDeal = RcvQueue.Dequeue();

                        //Debug.WriteLine(TCPReceiveDataDeal.Length, "TCPReceiveDataDeal_Length ");
                        for (int i = 0; i < ReceiveDataDeal.Length; i++) //窗体显示
                        {
                            strRcv += ReceiveDataDeal[i].ToString("X2") + " ";  //16进制显示
                        }
                        RcvTxt01.Text += strRcv + "\r\n";
                    }
                    else continue;
                }
                catch
                {
                    break;
                }
            }
        }

我感觉是解析线程的while循环的问题,因为一般耗cpu的就是while循环,但我想不出如何不使用while来循环不停的处理数据,我的应用程序必须是有数据就解析。。。
希望懂的人能给一点建议或能实现的方法,有源代码更好,多谢。。。

8分
else continue;
改为
else Thread.Sleep(1);

毕竟你处理数据是非常快的,那么大部分时间队列里其实都没有数据,一旦有数据也在几ns之内处理掉了
那么你就相当于while死循环在空转,能不吃CPU吗

2分
如果你写else continue;
那么其实根本不需要写else
反正不进if,后面也没有其他代码,还是回到while重新执行
引用 1 楼 Z65443344 的回复:

else continue;
改为
else Thread.Sleep(1);

毕竟你处理数据是非常快的,那么大部分时间队列里其实都没有数据,一旦有数据也在几ns之内处理掉了
那么你就相当于while死循环在空转,能不吃CPU吗

引用 2 楼 Z65443344 的回复:

如果你写else continue;
那么其实根本不需要写else
反正不进if,后面也没有其他代码,还是回到while重新执行

多谢回答,就是这个continue的问题,其实可以不写else continue;这条语句的。但神奇的是为什么使用Thread.Sleep(1)之后的CPU暂用率就变成0,即使是有数据解析时的暂用率也只有3-5,太神奇了!我感觉即使线程休眠1ms,不停的while循环也会很吃CPU的,给我解答一下吧。原谅我的小白疑惑,我只是不想做知其然,不知其所以然的事。。。再次感谢於黾君的回答!

2分
引用 3 楼 u012558127 的回复:
Quote: 引用 1 楼 Z65443344 的回复:

else continue;
改为
else Thread.Sleep(1);

毕竟你处理数据是非常快的,那么大部分时间队列里其实都没有数据,一旦有数据也在几ns之内处理掉了
那么你就相当于while死循环在空转,能不吃CPU吗

引用 2 楼 Z65443344 的回复:

如果你写else continue;
那么其实根本不需要写else
反正不进if,后面也没有其他代码,还是回到while重新执行

多谢回答,就是这个continue的问题,其实可以不写else continue;这条语句的。但神奇的是为什么使用Thread.Sleep(1)之后的CPU暂用率就变成0,即使是有数据解析时的暂用率也只有3-5,太神奇了!我感觉即使线程休眠1ms,不停的while循环也会很吃CPU的,给我解答一下吧。原谅我的小白疑惑,我只是不想做知其然,不知其所以然的事。。。再次感谢於黾君的回答!

因为在做一个死循环的判断

1分
Sleep(1) 将使计算频率降到每秒1千次,如果省掉,则以一个CPU100%的马力,会不会达到每秒1亿次以上?很容易理解的.
直接用serialPort_DataReceived事件来实现控制是最好的,如果一定要用一个线程,不妨用AutoResetEvent来同步.
5分
Sleep(1)  并不会让你的程序真的休眠1毫秒然后执行,因为windows的机制根本不是1毫秒以内就切换一次线程的。因此你写 Sleep(1),这是一种“自我安慰法”,实际上会等待十几倍甚至几十倍的时间之后才继续运行。

多线程处理程序,当有数据需要处理时,向系统线程池里注册一个处理过程(它包括要处理的数据)就行了。系统线程池本身就是一个队列,而且它知道如何比较好地调度多线程过程。

好的多线程程序,不需要可以出现什么“死循环、阻塞”的代码。你用不着去写什么“任务队列”,更用不着写什么 DataDealThread.Start() 语句。

你的那种 Sleep(1) 代码,首先它实际执行时远远不止阻塞1毫秒,其次它只是让程序“发呆”而这段时间什么都做不了。

而你的while循环里边的程序,根本没有让不同的处理任务能够合理地并发执行,实际上你的cpu占用率很低是因为“你的数据处理程序其实不过是一个单线程的”。

我要强调一下,所谓“生产者-消费者模型”是那些学习java的初学者爱唠叨的模式。

而你在.net中要自己设计一个线程池(并且可以自动优化性能)?

如果没有这个能力,那就先去使用.net的系统线程池。别仅仅重复初学者那一套,不要因为模式的名词儿挺时髦就自己开发。

引用 5 楼 tcmakebest 的回复:

Sleep(1) 将使计算频率降到每秒1千次,如果省掉,则以一个CPU100%的马力,会不会达到每秒1亿次以上?很容易理解的.
直接用serialPort_DataReceived事件来实现控制是最好的,如果一定要用一个线程,不妨用AutoResetEvent来同步.

这种方法值得推荐。使用啥线程池啥的纯粹新手瞎扯。

2分
可以让你的线程sleep一下。
引用 7 楼 sp1234 的回复:

你的那种 Sleep(1) 代码,首先它实际执行时远远不止阻塞1毫秒,其次它只是让程序“发呆”而这段时间什么都做不了。

而你的while循环里边的程序,根本没有让不同的处理任务能够合理地并发执行,实际上你的cpu占用率很低是因为“你的数据处理程序其实不过是一个单线程的”。

多谢回答!看来以后要多尝试。。。

引用 5 楼 tcmakebest 的回复:

Sleep(1) 将使计算频率降到每秒1千次,如果省掉,则以一个CPU100%的马力,会不会达到每秒1亿次以上?很容易理解的.
直接用serialPort_DataReceived事件来实现控制是最好的,如果一定要用一个线程,不妨用AutoResetEvent来同步.

嗯,好的,多谢回答,我会多尝试的。。。


CodeBye 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权 , 转载请注明C# 占用CPU的问题
喜欢 (0)
[1034331897@qq.com]
分享 (0)

文章评论已关闭!