在线程中的无限循环中,cpu使用率增加到100%

Meh*_*met 7 c# asp.net multithreading cpu-usage infinite-loop

我在ASP.NET Web应用程序中实现了一个基于Web的聊天平台,我使用类似于长轮询的技术.我的意思是我将来自客户端的每个Web请求保留特定时间段(超时)或直到新消息到达,然后将响应发送到客户端.

我将连接的客户端保留在内存中(字典对象),当有新消息发送到客户端时,我将此消息写入接收方客户端的消息数组中.客户端需要发送请求以获取自己的消息,并将此请求保存在内存中的数组中.

我正在使用异步http处理程序来监听客户端请求,我将Web请求保存在内存中的数组中.我使用线程从内存中连续检查新消息(在为每个客户端创建的字典中).

我不使用.net线程池线程来检查新消息或超时web请求.我创建这样的线程:

System.Threading.Thread t = new Thread(new ThreadStart(QueueCometWaitRequest_WaitCallback));
t.IsBackground = false;
t.Start();
Run Code Online (Sandbox Code Playgroud)

在每个线程的QueueCometWaitRequest_WaitCallback方法中,我处于无限循环中:

while (true)
{
...
Thread.Sleep(100);
}
Run Code Online (Sandbox Code Playgroud)

在这个方法中,我正在检查Web请求超时或每个Web请求的新消息,它也保存在内存中的数组中.

一切都很好,直到我注意到CPU使用率达到了100%的时间.(在第一个连接的客户端之后的几分钟内)在第一个请求开始时,一切似乎都正常,我的意思是在向客户端返回响应时CPU使用率不高于10%.但即使有2个客户端,CPU使用率也会增加到100%.只有在写入客户端请求的响应时,CPU使用率似乎是100%.如果没有客户端,那么一切都恢复正常(CPU使用率约为0%),直到客户端完成新的Web请求.

我不太详细地知道线程,但我怀疑我创建并无限运行的新线程.这就像操作系统因为它们一直在工作而及时为它们提供更多的CPU使用和资源,并且这个Thread.Sleep(100)不起作用.

这是QueueCometWaitRequest_WaitCallback()方法:

void QueueCometWaitRequest_WaitCallback()
{
   while (true)
   {
      if (processRequest.Length == 0)
      {
          Thread.Sleep(100);
      }
      else
      {
          for (int i = 0; i < processRequest.Length; i++)
          {
               Thread.Sleep(100);

               // below I am checking for new message or request time out 
               .................
               .................

               // If new message or time out I write to response
          }
      }    
   }
}
Run Code Online (Sandbox Code Playgroud)

我希望我能解释一下这种情况,我也对任何建议持开放态度(比如以不同的方式实施)

如果你能帮我解决这个问题,我将非常感谢,谢谢

Dr.*_*ABT 9

就像一般的最佳实践注释而不是直接回答一样 - 在消息接收器线程中编写Thread.Sleep(100)并不可取.一个更好的方法是使用前面提到的Thread.Join或ManualResetEvent等待句柄.例如,您可以像这样编码:

private ManualResetEvent waitHandle;
private object syncRoot = new object();
private bool isRunning = false;

void CreateThread()
{
    this.waitHandle = new ManualResetEvent(false);

    isRunning = true; // Set to false to kill the thread
    System.Threading.Thread t = new Thread(new ThreadStart(QueueCometWaitRequest_WaitCallback));         
    t.IsBackground = false; 
    t.Start();
}

void PushData()
{
    // On incoming data, push data into the processRequest queue and set the waithandle
    lock(syncRoot)
    {
        processRequest.Add(/* ... your data object to process. Assumes this is a queue */);
        waitHandle.Set(); // Signal to the thread there is data to process
    }
}

void QueueCometWaitRequest_WaitCallback() 
{    
    while (isRunning)    
    {       
        // Waits here using 0% CPU until the waitHandle.Set is called above
        this.waitHandle.WaitOne();

        // Ensures no-one sets waithandle while data is being processed and
        // subsequently reset
        lock(syncRoot)
        {
            for (int i = 0; i < processRequest.Length; i++)           
            {                        
                // Process the message. 
                // What's the type of processRequest? Im assuming a queue or something     
            }       

            // Reset the Waithandle for the next requestto process
            this.waitHandle.Reset();
        }
    }        
} 
Run Code Online (Sandbox Code Playgroud)

这将确保您的线程在等待时使用0%的CPU,并且只在有工作时消耗CPU.

如果不这样,您是否考虑过针对异步双向消息传递的第三方解决方案?我使用RabbitMQ(AMQP)在.NET应用程序中取得了巨大成功,可以处理高吞吐量的消息传递.RabbitMQ的API意味着您在收到消息后会收到一个事件,然后可以在后台线程上处理.

最好的祝福,

  • @Mehmet我会认真推荐将RabbitMQ作为第三方异步消息传递解决方案.这将处理点对点(一个客户端,一个服务器),多播(服务器到所有客户端)之间的消息管道,CPU使用率低,吞吐量高.您可以通过在服务器上实现Timer来实现对所有客户端的定期状态更新,如果没有收到新通知,则向所有客户端发送消息. (2认同)