2014-02-26 217 views
1

我有一個消費者爲生產者消費者圖案的一部分:生產者/消費者 - 生產者使用高CPU

簡化:

public class MessageFileLogger : ILogger 
{ 
    private BlockingCollection<ILogItem> _messageQueue; 
    private Thread _worker; 
    private bool _enabled = false; 
    public MessageFileLogger() 
    { 
     _worker = new Thread(LogMessage); 
     _worker.IsBackground = true; 
     _worker.Start(); 
    } 

    private void LogMessage() 
    { 
     while (_enabled) 
     { 
      if (_messageQueue.Count > 0) 
      { 

       itm = _messageQueue.Take(); 
       processItem(itm); 
      } 
      else 
      { 
       Thread.Sleep(1000); 
      } 
     } 
    } 
} 

如果刪除了

Thread.Sleep(1000); 

的CPU用法爬到一個非常高的(13%),而不是0%,設置線程睡覺。另外,如果我實例化類的多個實例,則CPU使用率以13%的增量上升,並且每個實例都會增加13%。

每隔一分鐘左右(可能每隔30秒)將一個新的LogItem添加到BlockingCollection中,並將適用的消息寫入文件。

是否有可能線程以某種方式阻止其他線程運行,並且系統需要補償?

更新: 更新代碼,以更好地反映實際的代碼

+1

即使隊列中沒有任何內容,您的發佈代碼也會處理項目。 –

回答

1

你給線程代碼運行,因此默認情況下它運行的代碼(while循環)一樣快,因爲它可能可以在一個單一的邏輯核心。由於這大約是13%,我想你的CPU有4個超線程核心,產生8個邏輯核心。每個線程儘可能快地運行它的while循環,從而產生13%的使用率。非常簡單。

不使用睡眠的副作用是整個系統運行速度較慢,並且使用/產生更多的電池/熱量。

一般來說,正確的方法是給_messageQueue

bool BlockingCollection::TryTake(type& item, std::chrono::milliseconds time) 
{ 
    DWORD Ret = WaitForSingleObject(event, time.count()); 
    if (Ret) 
     return false; 
    item = Take(); //might need to use a shared function instead of calling direct 
    return true; 
} 

然後另一種方法你的循環很簡單:

private void LogMessage() 
{ 
    type item; 
    while (_enabled) 
    { 
     if (_messageQueue.Take(item, std::chrono::seconds(1))) 
      ;//your origional code makes little sense, but this is roughly the same     
     processItem(itm); 
    } 
} 

這也意味着,如果一個項目的過程中可隨時添加阻擋部分,它立即在上執行,而不是整整一秒後。

+0

是的,我注意到我的粉絲很快就打開了。是添加一個Thread.Sleep方法的常用解決方案?如果不是,你能指出我正確的做事方式嗎? – TruthOf42

+0

@TruthOf42:添加回答 –