制作人/消费者 - 使用高CPU的制作人

时间:2014-02-26 19:39:09

标签: thread-safety sleep cpu-usage

我有一个消费者作为生产者消费模式的一部分:

简化为:

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%的增量爬升。

每隔一分钟左右(可能每30秒)添加一个新的LogItem BlockingCollection,并将适用的消息写入文件。

线程是否有可能阻止其他线程运行,系统需要以某种方式进行补偿?

更新: 更新了代码以更好地反映实际代码

1 个答案:

答案 0 :(得分:1)

您提供了运行的线程代码,因此默认情况下它会在单个逻辑核心上尽可能快地运行该代码(while循环)。由于这大约是13%,我想你的CPU有4个超线程内核,产生8个逻辑内核。每个线程以尽可能快的速度运行它的核心,导致另外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);
    }
}

这也意味着如果在阻止部分期间的任何时候添加了一个项目,它会立即在 上行动,而不是在整整一秒之后。