我相信一个很常见的情况是有一个待处理的项目队列,需要每次处理N个。
例如...如果我们有23个
项目,并且应该每次处理10个
,那么就像这样:
Process batch of 10
Process batch of 10
Process batch of 3
我可以用多种方式解决这个问题。我的问题是:.NET框架是否提供了任何专门解决这种情况的类? Queue
类非常完美,但它不允许一次出队多个项目。我相信一个很常见的情况是有一个待处理的项目队列,需要每次处理N个。
例如...如果我们有23个
项目,并且应该每次处理10个
,那么就像这样:
Process batch of 10
Process batch of 10
Process batch of 3
我可以用多种方式解决这个问题。我的问题是:.NET框架是否提供了任何专门解决这种情况的类? Queue
类非常完美,但它不允许一次出队多个项目。你可以在 Queue<T>
上创建一个扩展方法:
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
return yield
是线程安全的。我建议在处理出列时更加明确。public static IEnumerable<T> DequeueChunk<T>(this Queue<T> queue, int chunkSize) { var result = new List<T>(); for (var i = 0; i < chunkSize && queue.Count > 0; i++) { result.Add(queue.Dequeue()); } return result; }
- Simon K使用Linq,可以在.NET中通过使用Enumerable.Range()
方法和Select()
扩展方法来实现此目标:
var chunk = Enumerable.Range(0, chuckCount).Select(i => queue.Dequeue()).ToList();
这是通过生成一个整数的枚举器,然后对新枚举器中的每个整数出队列一个项目实现的。通过调用ToList()
确保立即执行该操作。
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();
chunk=>HandleChunck(chunk)
这个操作将会对每10个项目执行一次(chunk将包含10个项目)。但是,它如何知道应该处理最后3个项目,即使我们没有达到30个项目?这是因为Complete方法吗?只有在调用Complete时,进程才会开始吗? - Andre Pena我可能只会使用一个简化版本,从队列中出列并在特定时间间隔内使用计时器或系统中可用的任何东西执行操作。
所以经过10秒钟,如果有10个项目,则出列并处理;或者如果有100个,则同样如此。所有这些都取决于负载、正在完成的工作等因素,以及您尝试实现的延迟和响应的期望等等......
我认为您使用队列是为了不需要立即结果,而是需要在较长时间内执行的内容,例如数据聚合。
然后这就没有严格的SLA窗口。这可能需要一些基准测试和测试才能理解负载是什么,以及首选时间间隔是多少。
public static IEnumerable<T> DequeueAvailable<T>(this Queue<T> queue)
{
for (int i = 0; i < queue.Count; i++)
{
yield return queue.Dequeue();
}
}
queue.Count
都会减少,因此你只会出队列大约一半的项目(即当i
超过queue.Count
时)。循环应该改为while (queue.Count > 0)
。 - nollidge
IEnumerable
的出队对象。 - Andrew Whitaker