【问题标题】:Consume a ConcurrentQueue in a Linq statement在 Linq 语句中使用 ConcurrentQueue
【发布时间】:2011-09-09 23:27:23
【问题描述】:

如果我有一个 ConcurrentQueue,有没有一种首选的方式来使用 Linq 语句来使用它?它没有将所有项目作为序列出列的方法,并且它的枚举器不会删除项目。

我正在进行批量消费,这意味着我想定期处理队列并将其清空,而不是处理它直到它为空并阻塞直到更多项目入队。 BlockingCollection 似乎不会起作用,因为它会在到达最后一项时阻塞,并且我希望该线程执行其他操作,例如清除其他队列。

static ConcurrentQueue<int> MyQueue = new ConcurrentQueue<int>();
void Main()
{
    MyQueue.Enqueue(1);MyQueue.Enqueue(2);MyQueue.Enqueue(3);MyQueue.Enqueue(4);MyQueue.Enqueue(5);

    var lst = MyQueue.ToLookup(x => x.SomeProperty);
    //queue still has all elements
    MyQueue.Dump("queue");  
}

目前,我已经制作了一个辅助方法

static IEnumerable<T> ReadAndEmptyQueue<T>(this ConcurrentQueue<T> q)
{
    T item;
    while(q.TryDequeue(out item))
    {
        yield return item;
    }
}

var lk = MyQueue.ReadAndEmptyQueue().ToLookup(x => x.SomeProperty);
MyQueue.Dump(); //size is now zero

有没有更好的方法,还是我做对了?

【问题讨论】:

  • 我觉得不错。 ConcurrentQueue 上除了TryDequeue 之外没有其他方法可以出队。您的扩展方法看起来是使其成为 LINQable 的正确方法。

标签: c# .net-4.0 concurrent-collections


【解决方案1】:

在我看来,您的方法非常合理。允许消费者以这种方式清空队列既干净又简单。

BlockingCollection 似乎不起作用,因为它会在到达最后一项时阻塞,我希望该线程执行其他操作,例如清除其他队列。

我要提到的一件事 - 有时,从设计的角度来看,只为每个队列启动一个单独的消费者线程会更容易。如果你这样做,每个BlockingCollection&lt;T&gt; 可以只使用GetConsumingEnumerable() 并根据需要阻止,因为当队列为空时它们将处于等待状态。

这是我更常采用的方法,因为从同步的角度来看,如果每个集合都有一个或多个专用消费者,而不是消费者在其所消费的内容之间切换,它通常会简单得多。

【讨论】:

  • 是的,我同意通常的方法要简单得多,但我在网站上这样做,所以我想限制我使用的工作线程的数量。
  • @dan:那么您当前的方法非常好。如果您尝试不使用任何额外的线程,这似乎相当优雅。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多