CPU使用率问题

3

我有一个网络项目,其中没有计时器。只有一个TCP客户端连接到服务器并监听从网络接收任何数据。

         TcpClient _TcpClient = new TcpClient(_IpAddress, _Port);
        _ConnectThread = new Thread(new ThreadStart(ConnectToServer));
        _ConnectThread.IsBackground = true;
        _ConnectThread.Start();


    private void ConnectToServer()
    {
        try
        {
            NetworkStream _NetworkStream = _TcpClient.GetStream();
            byte[] _RecievedPack = new byte[1024 * 1000];
            string _Message = string.Empty;
            int _BytesRead;
            int _Length;

            while (_Flage)
            {
                _BytesRead = _NetworkStream.Read(_RecievedPack, 0, _RecievedPack.Length);
                _Length = BitConverter.ToInt32(_RecievedPack, 0);
                _Message = UTF8Encoding.UTF8.GetString(_RecievedPack, 4, _Length);

                if (_BytesRead != 0)
                {
                    //call a function to manage the data

                    _NetworkStream.Flush();
                }
            }
        }
        catch (Exception exp)
        {                
            // call a function to alarm that connection is false
        }
    }

但是一段时间之后,我的应用程序的CPU使用率会上升(90%,85%,...),即使没有接收到任何数据。请问有人可以给我一些关于CPU使用率的提示吗?我完全茫然无措,不知道应该检查项目的哪个部分!

3
我有点困惑这段代码 - 你没有检查 _BytesRead,但那似乎是数据的基础,否则你不知道是否有完整的消息...?另外 - 为什么读取时要刷新缓冲区? - Marc Gravell
5个回答

2

有人能给我关于CPU使用的一些提示吗?

如果您花费大量时间等待某些条件成为真,则应考虑检查应用程序中的循环,例如while循环,这将占用大量CPU时间。例如:

while (true)
{}

或者

while (_Flag)
{
    //do something
}

如果while循环内执行的代码是同步的,那么线程将会占用大量的CPU周期。为了解决这个问题,您可以在不同的线程中执行while内的代码,使其变成异步的,然后使用ManualResetEventAutoResetEvent来报告操作执行的情况。另外需要注意的是考虑使用System.Threading.Thread.Sleep方法让线程休眠一段时间,以便给CPU时间执行其他线程,例如:
while(_Flag)
{
    //do something

    Thread.Sleep(100);//Blocks the current thread for 100 milliseconds
}

1

我怀疑当 while 循环仍在运行时,连接的另一端被关闭,这种情况下,你将会从网络流中重复读取零字节(表示连接已关闭,参见 MSDN 上的 NetworkStream.Read)。

由于根据MSDN,NetworkStream.Read将会立即返回,因此你将停留在一个紧密的 while 循环中,这将消耗大量处理器时间。尝试添加 Thread.Sleep() 或在循环内检测“零读取”。理想情况下,你应该通过终止连接来处理读取零字节。

while (_Flage)
{
    _BytesRead = _NetworkStream.Read(_RecievedPack, 0, _RecievedPack.Length);
    _Length = BitConverter.ToInt32(_RecievedPack, 0);
    _Message = UTF8Encoding.UTF8.GetString(_RecievedPack, 4, _Length);

    if (_BytesRead != 0)
    {
        //call a function to manage the data

        _NetworkStream.Flush();
    }
}

1

你的代码存在几个问题... 在我看来,最重要的问题是:

  • 使用异步方法(BeginRead等),而不是阻塞方法,并且不要创建自己的线程。线程是“昂贵”的资源 - 在线程中使用阻塞调用因此是一种资源浪费。使用异步调用让操作系统在事件发生时(例如接收到数据)回调您,因此不需要单独的线程(回调使用池化线程运行)。
  • 请注意,Read可能只返回几个字节,它不必填充_ReceivedPack缓冲区。理论上,它可能只接收到一个或两个字节 - 还不足以调用ToInt32

1

因为你有一个while循环,如果没有从网络接收到任何数据,它就不会执行任何操作,所以CPU使用率会飙升。在其末尾添加Thread.Sleep(),如果没有接收到数据,则CPU使用率将恢复正常。

并且采纳Lucero给你的建议。


0
你是否已经附加了调试器并逐步执行代码,以查看它是否按照你的预期运行?
或者,如果你有一个可用的性能分析工具(如ANTs),那么它将帮助你看到应用程序中花费时间的地方。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接