【问题标题】:Is there a C# equivalent to Java's BlockingQueue.drainTo(Collection) method?是否有与 Java 的 BlockingQueue.drainTo(Collection) 方法等效的 C#?
【发布时间】:2017-02-03 04:58:51
【问题描述】:

我正在构建一个多线程 C# 应用程序,其中多个线程对队列中的元素做出贡献。单个线程正在使用同一队列中的元素。我希望单线程对传入元素的元素进行一些减少/合并,因此理想情况下它会查看队列中的所有新元素,减少它们,然后在减少后处理条目。有点像这样:

while (true)
{
  Collection<Elem> elements = queue.TakeAll();
  Collection<Elem> reducedElements = Reduce(elements);
  for (Elem e in reducedElements)
  {
    process(e);
  }
}

但显然没有任何 TakeAll() 方法。从 Java 经验来看,我已经习惯了 BlockingQueue's drainTo method,它提供了我感兴趣的东西。

我可以自己实现一些东西,只需使用 TryTake 直到队列为空。但这具有生产线程也可能忙于生产的风险,这将导致收集没有有限的结束来减少和处理。我基本上是在寻找一种方法将所有内容从队列中取出,将其留空,但提供一个可以处理的集合。

【问题讨论】:

  • 好的 api 设计不知道要添加什么,而是知道要包含什么。 TryDrainTo() 和“此操作的行为未定义......”肯定使它很早就出现在切割清单上。线程安全是 .NET 风格的主要设计目标,当您添加自己的(扩展)方法时不要忽视这一点。
  • 好吧,那么它可能会提供类似的方法,例如 TryTakeAll() 或类似的方法。现在看来我没有办法在特定时间点以原子方式取出队列中的所有元素。在我开始取出元素的那一刻,制作人可能会同时添加更多元素。

标签: c# multithreading queue


【解决方案1】:

查看命名空间 System.Collections.Concurrent 中的 ConcurrentQueue

此队列用于线程安全操作。

您可以根据自己的目的轻松添加扩展方法。

public static class Extensions
{
    public static List<T> DrainTo<T>(this System.Collections.Concurrent.ConcurrentQueue<T> poConcurrentQueue)
    {
        List<T> loList = new List<T>();
        T loElement;
        while (poConcurrentQueue.TryDequeue(out loElement))
            loList.Add(loElement);
        return loList;
    }
}

并像这样使用:

System.Collections.Concurrent.ConcurrentQueue<string> loConcurrentQueue = new System.Collections.Concurrent.ConcurrentQueue<string>();

loConcurrentQueue.Enqueue("Element1");
loConcurrentQueue.Enqueue("Element2");

var loList = loConcurrentQueue.DrainTo();

【讨论】:

  • 这并不像 drainTo 那样为您提供类似的保证。也就是说,您以原子方式获取所有元素,这意味着发布者被阻止添加更多元素,直到耗尽停止。如果没有这种保证,您可能会发生无限循环,由于发布繁忙,您永远无法到达队列的末尾。
猜你喜欢
  • 2013-06-03
  • 1970-01-01
  • 2010-12-23
  • 1970-01-01
  • 1970-01-01
  • 2012-02-17
  • 2021-09-17
  • 2013-07-25
  • 2019-03-07
相关资源
最近更新 更多