65

ConcurrentQueue.Net和.Net有什么区别BlockingCollection

BlockingCollection当可以通过 完成时,为什么最适合生产者-消费者操作ConcurrentQueue?我必须改进以下代码中的任何内容吗?

MessageSlotMachineGameStartOrAndStatusUpdate msg;

while (!aCancellationToken.IsCancellationRequested)
{
    try
    {
        this.isStillConsumingMsg = true;
        Boolean takeResult = this.msgQueue.TryTake(out msg, this.msgConsumeTimeOut, aCancellationToken);
        if (takeResult)
        {
            if (msg != null)
            {
                this.ProcessMessage(msg);
            }
        }
        else
        {
            break;
        }
    }
    catch (OperationCanceledException err)
    {
        EngineManager.AddExceptionLog(err, "Signal Operation Canceled");
    }
    catch (Exception err)
    {
        EngineManager.AddExceptionLog(err, "Signal exception");
    }
    finally
    {
        this.isStillConsumingMsg = false;
    }
}
4

2 回答 2

65

BlockingCollection有一个Take方法,如果没有东西可以阻止消费者,并等待生产者端提供一个项目。ConcurrentQueue缺少这样的方法——如果它是空的,消费者需要处理等待,生产者需要提供一个非空的通知。

于 2012-04-04T12:10:44.677 回答
13

BlockingCollection是并发集合的包装器,默认包装的集合是ConcurrentQueue ;-)

来自Microsoft BlockingCollection

创建 BlockingCollection 对象时,您不仅可以指定有界容量,还可以指定要使用的集合类型。例如,您可以为先进先出 (FIFO) 行为指定ConcurrentQueue对象,或为后进先出 (LIFO) 行为指定ConcurrentStack对象。您可以使用任何实现IProducerConsumerCollection接口的集合类。 BlockingCollection 的默认集合类型是 ConcurrentQueue。

BlockingCollection有一个Take()阻塞方法(因此得名),但它也有一个非常有趣的GetConsumingEnumerable()方法,它允许您无限循环:只有在将某些内容添加到集合时,代码才会进入代码内部的循环。请参阅albahari.com关于线程的优秀在线电子书。

以下是该网站的代码示例:

public class PCQueue : IDisposable
{
  BlockingCollection<Action> _taskQ = new BlockingCollection<Action>(); 
  public PCQueue (int workerCount)
  {
    // Create and start a separate Task for each consumer:
    for (int i = 0; i < workerCount; i++)
      Task.Factory.StartNew (Consume);
  }
 
  public void Dispose() { _taskQ.CompleteAdding(); }
 
  public void EnqueueTask (Action action) { _taskQ.Add (action); }
 
  void Consume()
  {
    // This sequence that we’re enumerating will block when no elements
    // are available and will end when CompleteAdding is called. 
    foreach (Action action in _taskQ.GetConsumingEnumerable())
      action();     // Perform task.
  }
}
于 2020-01-07T10:30:36.047 回答