Man*_*oon 17 c# task-parallel-library concurrent-queue
我之前没有使用过并发队列.
可以在while循环中使用如下所示的TryDequeue吗?难道这不会永远被卡住吗?
var cq = new ConcurrentQueue<string>();
cq.Enqueue("test");
string retValue;
while(!cq.TryDequeue(out retValue))
{
// Maybe sleep?
}
//Do rest of code
Run Code Online (Sandbox Code Playgroud)
Ser*_*rvy 13
它是安全的,因为循环实际上不会结束,直到它已经拉出一个项目,并且如果队列有一个要取出的项目它将最终结束.如果队列被另一个线程清空并且不再添加任何项目,那么循环当然不会结束.
除此之外,你所拥有的是一个繁忙的循环.实际上应该始终避免这种情况.要么你不断轮询队列要求更多的项目,浪费CPU时间和精力,或者你最终睡觉,因此一旦添加它就不会实际使用队列中的项目(即便如此,仍然浪费上下文切换的一些时间/精力只是为了轮询队列).
如果你发现自己处于想要"等到有一件物品可供我拿走"的位置,你应该做的是使用a BlockingCollection
.它被特别设计来包装各种类型的并发集合的和阻塞,直到有可用采取的项目.它允许您将代码更改queue.Take()
为更容易编写,从语义上说明您正在做什么,明确正确,明显更有效,以及完全安全.
qua*_*dev 12
是的,根据文档是安全的,但它不是推荐的设计.
如果在第一次调用TryDequeue时队列为空,它可能会"永远陷入困境",如果在该点之后没有其他线程在队列中推送数据(你可以在N次尝试之后或超时之后打破).
ConcurrentQueue提供了一个IsEmpty成员来检查队列中是否有项目.检查它比循环TryDequeue调用(特别是如果队列通常为空)要高效得多
你可能想做的是:
while(cq.IsEmpty())
{
// Maybe sleep / wait / ...
}
if(cq.TryDequeue(out retValue))
{
...
}
Run Code Online (Sandbox Code Playgroud)
编辑:如果这最后调用返回false:另一个你的线程出列的项目.如果你没有其他线程,这是安全的,如果你这样做,你应该使用while(TryDequeue)