The PriorityQueue<TElement, TPriority> https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.priorityqueue-2类没有提供将其用作IEnumerable
盒子外面。它只有一个UnorderedItems https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.priorityqueue-2.unordereditems财产,这不是你想要的。此属性产生队列的内容而不消耗它们,并且不按特定顺序。虽然实现自定义很容易GetConsumingEnumerable
方法为PriorityQueue<TElement, TPriority>
类,像这样:
/// <summary>
/// Gets an enumerable sequence that consumes the elements of the queue
/// in an ordered manner.
/// </summary>
public static IEnumerable<(TElement Element, TPriority Priority)>
GetConsumingEnumerable<TElement, TPriority>(
this PriorityQueue<TElement, TPriority> source)
{
while (source.TryDequeue(out TElement element, out TPriority priority))
{
yield return (element, priority);
}
}
使用示例:
var partitioner = Partitioner.Create(activeTasksPriority.GetConsumingEnumerable(),
EnumerablePartitionerOptions.NoBuffering);
Parallel.ForEach(partitioner, options, entry =>
{
var (t, priority) = entry;
Console.WriteLine($"Priority: {priority}, Task: {t}");
Thread.Sleep(100);
});
的意图Partitioner.Create https://learn.microsoft.com/en-us/dotnet/api/system.collections.concurrent.partitioner.create+NoBuffering https://learn.microsoft.com/en-us/dotnet/api/system.collections.concurrent.enumerablepartitioneroptions是为了防止Parallel.ForEach
在准备好处理元素之前提前消耗元素并将它们存储到缓冲区中。
Note:这个答案涉及问题中提出的简单场景,其中PriorityQueue<E,P>
在开始并行循环之前已完全填充。如果您想在循环运行时在队列中添加更多项目,则不能直接使用PriorityQueue<E,P>
有两个原因:
- 它不是线程安全的集合。
- 它没有阻塞功能,因此循环可能会在处理所有项目之前提前完成。
如果你正在处理这样的场景,你可以看看这个问题:并发优先收集 https://stackoverflow.com/questions/23470196/concurrent-collection-with-priority.