簡體   English   中英

在線程中的無限循環中,cpu使用率增加到100%

[英]cpu usage increasing up to 100% in infinite loop in thread

我在ASP.NET Web應用程序中實現了一個基於Web的聊天平台,我使用類似於長輪詢的技術。 我的意思是我將來自客戶端的每個Web請求保留特定時間段(超時)或直到新消息到達,然后將響應發送到客戶端。

我將連接的客戶端保留在內存中(字典對象),當有新消息發送到客戶端時,我將此消息寫入接收方客戶端的消息數組中。 客戶端需要發送請求以獲取自己的消息,並將此請求保存在內存中的數組中。

我正在使用異步http處理程序來監聽客戶端請求,我將Web請求保存在內存中的數組中。 我使用線程從內存中連續檢查新消息(在為每個客戶端創建的字典中)。

我不使用.net線程池線程來檢查新消息或超時web請求。我創建這樣的線程:

System.Threading.Thread t = new Thread(new ThreadStart(QueueCometWaitRequest_WaitCallback));
t.IsBackground = false;
t.Start();

在每個線程的QueueCometWaitRequest_WaitCallback方法中,我處於無限循環中:

while (true)
{
...
Thread.Sleep(100);
}

在這個方法中,我正在檢查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
          }
      }    
   }
}

我希望我能解釋一下這種情況,我也對任何建議持開放態度(比如以不同的方式實施)

如果你能幫我解決這個問題,我將非常感謝,謝謝

就像一般的最佳實踐注釋而不是直接回答一樣 - 在消息接收器線程中編寫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();
        }
    }        
} 

這將確保您的線程在等待時使用0%的CPU,並且只在有工作時消耗CPU。

如果不這樣,您是否考慮過針對異步雙向消息傳遞的第三方解決方案? 我使用RabbitMQ (AMQP)在.NET應用程序中取得了巨大成功,可以處理高吞吐量的消息傳遞。 RabbitMQ的API意味着您在收到消息后會收到一個事件,然后可以在后台線程上處理。

最好的祝福,

我在內存中保持連接客戶端(字典對象)

如果靜態使用,字典對象不是線程安全的。 如果將它用作靜態成員,則需要創建一個Lock語句。

這是一個從Log4Net LoggerFactory類中提取的示例...請注意,TypeToLoggerMap是一個字典對象,當它引用了GetLogger方法時,使用了一個Lock語句。

public static class LoggerFactory
{
    public static ILogger GetLogger(Ninject.Activation.IContext context)
    {
        return GetLogger(context.Request.Target == null ? typeof(ILogger) : context.Request.Target.Member.DeclaringType);
    }

    private static readonly Dictionary<Type, ILogger> TypeToLoggerMap = new Dictionary<Type, ILogger>();

    private static ILogger GetLogger(Type type)
    {
        lock (TypeToLoggerMap)
        {
            if (TypeToLoggerMap.ContainsKey(type))
                return TypeToLoggerMap[type];

            ILogger logger = new Logger(type);
            TypeToLoggerMap.Add(type, logger);

            return logger;
        }
    }
}

看看這篇文章 - 這是我發現有關Dictionary對象的上述信息的地方。

https://www.toptal.com/dot-net/hunting-high-cpu-usage-in-dot-net

作為旁注,您是否考慮過將SignalR用於您的項目?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM