【问题标题】:What are the differences between ConcurrentQueue and BlockingCollection in .Net?.Net 中的 ConcurrentQueue 和 BlockingCollection 有什么区别?
【发布时间】:2012-04-18 03:20:23
【问题描述】:

.Net 中ConcurrentQueueBlockingCollection 有什么区别?

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

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;
    }
}

【问题讨论】:

  • BlockingCollection 使用 CurrentQueue 作为底层类型来保存数据。此外,它还具有阻止功能。
  • 还要注意 BlockingCollection 默认使用 ConcurrentQueue,但是您可以在实现 IProducerConsumerCollection 的构造函数中指定另一个集合类型...例如,如果您想要 LIFO,您可以指定一个 ConcurrentStack 来代替

标签: .net generics c#-4.0


【解决方案1】:

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

【讨论】:

  • @WAPGuy 您可以使用AutoResetEvent。点击链接并向下滚动以查看其使用方式的示例。
  • 好的,当它向 WaitHandle 发出信号时?当它为空或 Take 方法超时后立即?
  • @WAPGuy 它立即发出信号。超时时间跨度是为了确保如果在给定的超时时间内没有信号,该方法不会永远挂起。
  • 关于拍摄顺序?两者都是先进先出?
  • @JohnDemetriou 默认情况下,BlockingCollection 包含ConcurrentQueue,所以答案是“是”。但是,您可以构造 BlockingCollection 对象,其中包含其他集合,以更改“获取”的顺序。
【解决方案2】:

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

来自Microsoft BlockingCollection

当你创建一个 BlockingCollection 对象时,你可以指定 not 只有有限的容量,还有要使用的集合类型。为了 例如,您可以为先入指定一个 ConcurrentQueue 对象, 先出 (FIFO) 行为,或用于后进的 ConcurrentStack 对象, 先出(LIFO)行为。您可以使用任何集合类 实现 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.
  }
}

【讨论】:

    猜你喜欢
    • 2011-02-13
    • 1970-01-01
    • 2010-11-14
    • 1970-01-01
    • 2015-10-27
    • 2011-10-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多