【问题标题】:Is there a .NET queue class that allows for dequeuing multiple items at once?是否有一个允许一次将多个项目出列的 .NET 队列类?
【发布时间】:2016-02-06 16:10:59
【问题描述】:

我相信一个非常常见的场景是有一个应该一次处理 N 个项目的队列。

例如..如果我们有23 items 并且应该一次处理10,它会像:

Process batch of 10
Process batch of 10
Process batch of 3

我可以通过多种方式解决这个问题。我的问题是:.NET 框架是否提供了专门为解决这种情况而设计的任何类? Queue 类将是完美的,但它不允许一次出列多个项目。

【问题讨论】:

  • 你不能循环出列 10 个项目然后处理它们吗?我是否从您的问题中遗漏了一些排除这种方法的内容?
  • 你为什么不把 10 个完整的批次排入队列?
  • 您可以构建一个扩展方法,以块的形式出列并返回出列对象的IEnumerable
  • 这些可以乱序排列还是混合排列?一些排队系统有对话(Service Broker)的概念,其中消息可以逻辑地组合在一起作为一个对话,这样它们就可以由单个阅读器处理,而其他消息可以由它们各自的阅读器处理。

标签: c# .net linq collections


【解决方案1】:

TPL 数据流库提供 BatchBlock < T > 将输入的消息序列分组为所需大小的块。

 var bb = new BatchBlock<int>(10);
 var ab = new ActionBlock<int[]>((Action<int[]>)chunk=>HandleChunk(chunk));  

 bb.LinkTo(ab, new DataflowLinkOptions(){PropogateCompletion = true});

 for(int i = 0; i < 23; ++i)
 {
     bb.Post(i);
 }

 bb.Complete();
 ab.Completion.Wait();

【讨论】:

  • 感谢您的回答。我很清楚:当您将Post 分配给BatchBlock 时,您正在分配要处理的数据。但一次只能处理 10 个。因此,Post 可能会阻塞 que 线程,直到某些项目返回。正确的?还是平行的?它可能是并行的,因为它来自 TPL 库
  • @andrerpena 没错。默认情况下,ActionBlock 按顺序处理消息。您可以通过在选项中指定 MaxDegreeOfParalIelism 来更改此行为。
  • 我明白了。谢谢。所以,我假设动作chunk=&gt;HandleChunck(chunk) 将为每 10 个项目执行一次(块将是 10 个项目)。但是,即使我们没有达到 30,它怎么知道它应该处理最后 3 个呢?是因为 Complete 方法吗?只有在调用 Complete 时才会启动该过程吗?
  • @andrerpena:一个小小的说明:BatchBlock.Post() 没有阻塞。它维护未决消息的内部缓冲区,直到它们被分组为块并被目标块(ActionBlock)使用
  • 那么 Complete() 方法会让“消费”启动?
【解决方案2】:

你可以在Queue&lt;T&gt;上创建一个扩展方法:

public static class QueueExtensions
{
    public static IEnumerable<T> DequeueChunk<T>(this Queue<T> queue, int chunkSize) 
    {
        for (int i = 0; i < chunkSize && queue.Count > 0; i++)
        {
            yield return queue.Dequeue();
        }
    }
}

用法:

var q = new Queue<char>();
q.DequeueChunk(10) // first 10 items
q.DequeueChunk(10) // next 10 items

示例: https://dotnetfiddle.net/OTcIZX

【讨论】:

    【解决方案3】:

    您可以通过使用Enumerable.Range() 方法和Select() 扩展方法在带有Linq 的.NET 中实现此目的:

    var chunk = Enumerable.Range(0, chuckCount).Select(i =&gt; queue.Dequeue()).ToList();

    它的工作原理是生成一个整数的可枚举,然后对于新可枚举中的每个整数,它将一个项目从队列中取出。通过调用 ToList() 确保操作立即完成。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-25
      • 1970-01-01
      • 1970-01-01
      • 2010-10-29
      • 2012-05-28
      相关资源
      最近更新 更多