并发队列性能不佳

时间:2018-02-22 03:56:41

标签: c# .net multithreading concurrency queue

我有两个主题。一种是从串行端口收集数据并将其放入一个数组中,然后将其添加到并发队列中。另一个线程是采用这些数组并实时绘制数据。每秒大约有150个数据包,每个50字节。 我遇到的问题是,当它运行时,它消耗大约10%的CPU。这是一个非常快速的核心I7 Haswell。如果我在消费线程中添加Thread.Sleep(1),则CPU利用率降至1%。问题是如果我把它放在Thread.Sleep(2)然后数据包不再同步。所以这不是一个解决方案,如果它在较慢的计算机上运行,​​它可能无法正常工作。

代码很简单。这是生产者线程:

    static void FillQueue(byte[] buffer)
    {
        dataQueue.Enqueue(buffer);
    }

这是消费者主题:

        while (continuePolling)
        {                
            Thread.Sleep(1); //if removed, there is 10% CPU utilization.  If higher then packet synchronization is lost.

            if (dataQueue.TryDequeue(out result))
            {
                ProcessPacket(result);
            }               
        }

我发现这很难理解,因为ProcessPacket方法执行大约需要0.3毫秒,并且每秒调用大约10秒。

我现在尝试使用阻止集合。 这是制片人

 BlockingCollection<byte[]> dataQueue = new BlockingCollection<byte[]>;

 public static void addData(buffer)
 {
      dataQueue.add(buffer);
 }

这是消费者

 while (dataQueue.TryTake(out result)
 {
     ProcessPacket(result);
 }

完全没有区别!它使用10%的CPU,如果我添加一个Thread.Sleep(1)就可以了,但是一个Thread.Sleep(2)并且我丢失了数据包 我不明白。每个数据包中有50个字节。而已。它们的消耗速度和生产速度一样快。 感谢

1 个答案:

答案 0 :(得分:7)

那是因为你基本上有while (true) {}循环。 ProcessPacket需要0.3毫秒,每秒有10个数据包,因此每秒3毫秒的有用工作量。剩余的997ms你的循环不断检查队列中是否有新项目,浪费你的CPU资源。

相反,将BlockingCollection与您的队列一起使用,这对您的任务有更好的选择。它支持阻塞出队(必要时带有超时和取消令牌),所以不要浪费CPU:

var dataQueue = new BlockingCollection<string>(new ConcurrentQueue<string>());
// Add instead of Enqueue
dataQueue.Add("some item");
// Take instead of Dequeue, this will block until item is available in queue
var result = dataQueue.Take();
// blocks until item is available or timeout happens
if (dataQueue.TryTake(out result, TimeSpan.FromMilliseconds(100)))

它还支持&#34;流媒体&#34;接口,所以你的代码可以只是:

foreach (var result in dataQueue.GetConsumingEnumerable()) {
    ProcessPacket(result);        
}

而不是continuePolling标志 - 调用

dataQueue.CompleteAdding();

当不再需要更多项目时(因此,您将continuePolling设置为false) - 这将使GetConsumingEnumerable完成提供项目并返回。