使用C#写了一个串口通信界面,使用的是队列的方式来处理数据,即将接收数据、数据解析分开,首先使用C#自带的serialPort_DataReceived函数接收数据,然后将接收到的数据加入到队列中。在载入界面时会打开数据解析线程,当队列中有数据时,数据解析线程会解析数据。遇到的问题是,查看任务管理器发现我的应用程序的cpu占用率达到了25,当我把解析线程注释掉后应用程序的cpu暂用率变为0,这就是解析线程太耗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之内处理掉了 |
2分 |
如果你写else continue;
那么其实根本不需要写else 反正不进if,后面也没有其他代码,还是回到while重新执行 |
多谢回答,就是这个continue的问题,其实可以不写else continue;这条语句的。但神奇的是为什么使用Thread.Sleep(1)之后的CPU暂用率就变成0,即使是有数据解析时的暂用率也只有3-5,太神奇了!我感觉即使线程休眠1ms,不停的while循环也会很吃CPU的,给我解答一下吧。原谅我的小白疑惑,我只是不想做知其然,不知其所以然的事。。。再次感谢於黾君的回答! |
|
2分 |
因为在做一个死循环的判断 |
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的系统线程池。别仅仅重复初学者那一套,不要因为模式的名词儿挺时髦就自己开发。 |
|
这种方法值得推荐。使用啥线程池啥的纯粹新手瞎扯。 |
|
2分 |
可以让你的线程sleep一下。
|
多谢回答!看来以后要多尝试。。。 |
|
嗯,好的,多谢回答,我会多尝试的。。。 |