我有两个主题。一种是从串行端口收集数据并将其放入一个数组中,然后将其添加到并发队列中。另一个线程是采用这些数组并实时绘制数据。每秒大约有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个字节。而已。它们的消耗速度和生产速度一样快。 感谢
答案 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
完成提供项目并返回。