没有Thread.Sleep的并发集合吃了太多的cpu [英] Concurrent collections eating too much cpu without Thread.Sleep
问题描述
BlockingCollection
或ConcurrentQueue
的正确用法是什么,以便您可以自由地使项目出队,而不会使用线程消耗掉一半或更多的CPU?
What would be the correct usage of either, BlockingCollection
or ConcurrentQueue
so you can freely dequeue items without burning out half or more of your CPU using a thread ?
我正在使用2个线程运行一些测试,除非我的Thread.Sleep至少为50〜100ms,否则它至少会占用我CPU的50%.
I was running some tests using 2 threads and unless I had a Thread.Sleep of at least 50~100ms it would always hit at least 50% of my CPU.
这是一个虚构的例子:
private void _DequeueItem()
{
object o = null;
while(socket.Connected)
{
while (!listOfQueueItems.IsEmpty)
{
if (listOfQueueItems.TryDequeue(out o))
{
// use the data
}
}
}
}
在上面的示例中,我将必须设置一个thread.sleep,这样CPU才不会崩溃.
With the above example I would have to set a thread.sleep so the cpu doesnt blow up.
注意:我也尝试了一段时间而不进行IsEmpty检查,结果是一样的.
Note: I have also tried it without the while for IsEmpty check, result was the same.
推荐答案
不是因为BlockingCollection
或ConcurrentQueue
,而是while循环:
It is not because of the BlockingCollection
or ConcurrentQueue
, but the while loop:
while(socket.Connected)
{
while (!listOfQueueItems.IsEmpty)
{ /*code*/ }
}
当然,这会降低CPU的性能;因为如果队列为空,则while循环就像:
Of course it will take the cpu down; because of if the queue is empty, then the while loop is just like:
while (true) ;
反过来会占用CPU资源.
which in turn will eat the cpu resources.
这不是使用ConcurrentQueue
的好方法,您应该将其与AutoResetEvent
一起使用,因此无论何时添加项目,您都会收到通知.
示例:
This is not a good way of using ConcurrentQueue
you should use AutoResetEvent
with it so whenever item is added you will be notified.
Example:
private ConcurrentQueue<Data> _queue = new ConcurrentQueue<Data>();
private AutoResetEvent _queueNotifier = new AutoResetEvent(false);
//at the producer:
_queue.Enqueue(new Data());
_queueNotifier.Set();
//at the consumer:
while (true)//or some condition
{
_queueNotifier.WaitOne();//here we will block until receive signal notification.
Data data;
if (_queue.TryDequeue(out data))
{
//handle the data
}
}
为了充分利用BlockingCollection
,您应该使用GetConsumingEnumerable()
等待添加项,例如:
For a good usage of the BlockingCollection
you should use the GetConsumingEnumerable()
to wait for the items to be added, Like:
//declare the buffer
private BlockingCollection<Data> _buffer = new BlockingCollection<Data>(new ConcurrentQueue<Data>());
//at the producer method:
_messageBuffer.Add(new Data());
//at the consumer
foreach (Data data in _buffer.GetConsumingEnumerable())//it will block here automatically waiting from new items to be added and it will not take cpu down
{
//handle the data here.
}
这篇关于没有Thread.Sleep的并发集合吃了太多的cpu的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!