并发集合在没有 Thread.Sleep 的情况下消耗了太多 cpu
BlockingCollection
或 ConcurrentQueue
的正确用法是什么,这样您就可以自由地将项目出队,而不会使用线程消耗一半或更多的 CPU ?
正在使用 2 个线程运行一些测试,除非我的 Thread.Sleep 至少为 50~100 毫秒,否则它总是会占用至少 50% 的 CPU。
这是一个虚构的例子:
private void _DequeueItem()
{
object o = null;
while(socket.Connected)
{
while (!listOfQueueItems.IsEmpty)
{
if (listOfQueueItems.TryDequeue(out o))
{
// use the data
}
}
}
}
对于上面的例子,我必须设置一个 thread.sleep,这样 cpu 就不会崩溃。
注意:我也尝试过没有进行 IsEmpty 检查,结果是相同的。
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 ?
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.
Here is a fictional example:
private void _DequeueItem()
{
object o = null;
while(socket.Connected)
{
while (!listOfQueueItems.IsEmpty)
{
if (listOfQueueItems.TryDequeue(out o))
{
// use the data
}
}
}
}
With the above example I would have to set a thread.sleep so the cpu doesnt blow up.
Note: I have also tried it without the while for IsEmpty check, result was the same.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
不是因为
BlockingCollection
或ConcurrentQueue
,而是因为while循环:当然会占用cpu;因为如果队列为空,那么 while 循环就像:
这反过来会消耗 cpu 资源。
这不是使用 ConcurrentQueue 的好方法,您应该使用 AutoResetEvent ,这样每当添加项目时您都会收到通知。
示例:
为了充分利用
BlockingCollection
,您应该使用GetConsumingEnumerable()
来等待添加项目,例如:It is not because of the
BlockingCollection
orConcurrentQueue
, but the while loop:Of course it will take the cpu down; because of if the queue is empty, then the while loop is just like:
which in turn will eat the cpu resources.
This is not a good way of using
ConcurrentQueue
you should useAutoResetEvent
with it so whenever item is added you will be notified.Example:
For a good usage of the
BlockingCollection
you should use theGetConsumingEnumerable()
to wait for the items to be added, Like:在这种情况下,您确实希望使用
BlockingCollection
类。它被设计为阻塞,直到队列中出现一个项目。这种性质的集合通常称为阻塞队列。这种特定的实现对于多个生产者和多个消费者来说是安全的。如果你尝试自己实现的话,这是非常难以做到的。如果您使用BlockingCollection
,您的代码将如下所示。如果队列为空,
Take
方法会自动阻塞。它以将线程置于 SleepWaitJoin 状态的方式进行阻塞,这样就不会消耗 CPU 资源。BlockingCollection
的巧妙之处在于它还使用低锁策略来提高性能。这意味着Take
将检查队列中是否有项目,如果没有,它将短暂执行旋转等待以防止上下文切换线。如果队列仍然为空,那么它将使线程进入睡眠状态。这意味着BlockingCollection
将具有ConcurrentQueue
在并发执行方面提供的一些性能优势。You really want to be using the
BlockingCollection
class in this case. It is designed to block until an item appears in the queue. A collection of this nature is often referred to as a blocking queue. This particular implementation is safe for multiple producers and multiple consumers. That is something that is surprisingly difficult to get right if you tried implementing it yourself. Here is what your code would look like if you usedBlockingCollection
.The
Take
method blocks automatically if the queue is empty. It blocks in a manner that puts the thread in theSleepWaitJoin
state so that it will not consume CPU resources. The neat thing aboutBlockingCollection
is that it also uses low-lock strategies to increase performance. What this means is thatTake
will check to see if there is an item in the queue and if not then it will briefly perform a spin wait to prevent a context switch of the thread. If the queue is still empty then it will put the thread to sleep. This means thatBlockingCollection
will have some of the performance benefits thatConcurrentQueue
provides in regards to concurrent execution.仅当队列为空时才可以调用 Thread.Sleep():
否则您应该考虑使用事件。
You can call
Thread.Sleep()
only when queue is empty:Otherwise you should consider to use events.