【问题标题】:TCP Server high CPU usageTCP 服务器 CPU 使用率高
【发布时间】:2015-08-05 05:56:19
【问题描述】:

C# Visual Studio 2013

我正在开发一个粗略的 TCP 服务器/客户端。它的工作原理是这样的:
客户端向服务器发送消息 > 服务器向客户端发送“响应”。我将其循环使用,因为我将在游戏中使用这种数据传输进行多人游戏。但是,我进行了性能测试,因为当连接三个以上的客户端时,我的 TCP 服务器正在使用我的大量 CPU。性能分析器表示,以下方法对 96% 的利用率负责。你能帮我解决这个问题吗?

private static void ReceiveCallback(IAsyncResult AR)
    {
        Socket current = (Socket)AR.AsyncState;
        int received;

        try
        {
            received = current.EndReceive(AR);
        }
        catch (SocketException)
        {
            Console.WriteLine("Client forcefully disconnected");
            current.Close(); // Dont shutdown because the socket may be disposed and its disconnected anyway
            _clientSockets.Remove(current);
            return;
        }

        byte[] recBuf = new byte[received];
        Array.Copy(_buffer, recBuf, received);
        string text = Encoding.ASCII.GetString(recBuf);
        Console.WriteLine("Received Text: " + text);


        string msg = "Response!";
        byte[] data = Encoding.ASCII.GetBytes(msg);
        current.Send(data);


        current.BeginReceive(_buffer, 0, _BUFFER_SIZE, SocketFlags.None, ReceiveCallback, current);
    }

以防万一,这里是调用 ReceiveCallback 的 AcceptCallback 方法。

private static void AcceptCallback(IAsyncResult AR)
    {
        Socket socket;

        try
        {
            socket = _serverSocket.EndAccept(AR);
        }
        catch (ObjectDisposedException) // I cannot seem to avoid this (on exit when properly closing sockets)
        {
            return;
        }

        _clientSockets.Add(socket);
        socket.BeginReceive(_buffer, 0, _BUFFER_SIZE, SocketFlags.None, ReceiveCallback, socket);
        Console.WriteLine("Client connected...");
        _serverSocket.BeginAccept(AcceptCallback, null);
    } 

【问题讨论】:

  • 96% 非常好,这意味着您没有被其他任何事情所困扰。删除 Console.WriteLine() 调用。
  • 应用程序本身跃升到我的总 CPU(8 核)的 50% 以上。我可以听到散热器风扇打开的声音。我找到了一种通过使用 Thread.Sleep(45) 将其保持在 1% 以下的方法;但是我听说从不使用 Thread.Sleep,所以这感觉像是一个花哨的解决方案。
  • 嗯,您是否在本地主机端点之间以最大速度发送数据?这应该会将 CPU 驱动到 100%。
  • 我是,添加线程睡眠延迟似乎可以解决它。我只是觉得这不是最佳的做法。
  • 您到底关心什么?如果您尝试尽可能快地运行,那么您当然会将 CPU 驱动到 100%。你为什么要改变它?怎么可能是其他方式?

标签: c# multithreading sockets tcp cpu-usage


【解决方案1】:

在 cmets 中,您说您的代码以 CPU 和网络允许的速度发送数据,但您想限制它。您可能应该考虑要发送的最佳频率是多少。然后,以该频率发送。

var delay = TimeSpan.FromMilliseconds(50);
while (true) {
 await Task.Delay(delay);
 await SendMessageAsync(mySocket, someData);
 await ReceiveReplyAsync(mySocket);
}

注意,我已经使用 await 来解开回调混乱。如果您现在将计时器或延迟添加到混音回调中,可能会变得笨拙。不过,您可以按照自己喜欢的方式进行操作。或者,您只需在后台线程/任务上使用同步套接字 IO。如果没有太多线程,那会更简单,也是首选方式。请注意,MSDN 通常无缘无故地使用带有套接字的 APM 模式。

注意,如果您想根据时间等待,Thread.Sleep/Task.Delay 完全可以使用。

【讨论】:

    【解决方案2】:

    你为什么这样做:

    byte[] recBuf = new byte[received];
    Array.Copy(_buffer, recBuf, received);
    string text = Encoding.ASCII.GetString(recBuf);
    

    您有一个复制操作,将接收到的缓冲区复制到 recBuf 中,然后再复制一个来创建字符串。你可以避免一个,你的表现会提高。但是cpu高是正常的,因为即使转换成字符串也会占用cpu。

    【讨论】:

    • 你是说我应该从 _buffer 中获取字符串而不是复制?
    • 是的,这是一个额外的复制操作,纯粹是浪费cpu功率。如果你不想高cpu负载,摆脱它并使用任务延迟,但可以删除复制操作并提高效率。请试一试,如果可行,请点赞。
    猜你喜欢
    • 1970-01-01
    • 2014-07-13
    • 2018-07-08
    • 2020-03-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-19
    相关资源
    最近更新 更多