BlockingCollection <>中的元素顺序

Mat*_*ite 12 .net queue collections concurrency multithreading

我有一个下载队列实现BlockingCollection<>.现在我想暂时优先考虑一些下载.我认为将一些元素"向上"移动可能会很棒,就像在列表中一样,但是没有像Remove()/ AddFirst()或Move()这样的方法.

安排物品的首选方式是BlockingCollection<>什么?

Bri*_*eon 17

不幸的是,没有办法以你想要的方式重新排列队列.你真正需要的是PriorityBlockingCollection作为优先级队列实现,但也不存在.

您可以做的是利用该TakeFromAny方法获得所需的优先级行为.TakeFromAny将从一组BlockingCollection实例中出列第一个可用项.它将优先考虑数组中首先列出的队列.

var low = new BlockingCollection<object> { "low1", "low2" };
var high = new BlockingCollection<object> { "high1", "high2" };
var array = new BlockingCollection<object>[] { high, low };
while (true)
{
  object item;
  int index = BlockingCollection<object>.TakeFromAny(array, out item);
  Console.WriteLine(item);
}
Run Code Online (Sandbox Code Playgroud)

上面的例子将打印:

high1
high2
low1
low2
Run Code Online (Sandbox Code Playgroud)

它会强制您使用多个队列,因此它不是最优雅的解决方案.


Ree*_*sey 8

BlockingCollection<T>通过包装内部工作IProducerConsumerCollection<T>.默认是在ConcurrentQueue<T>内部使用,但您可以通过此构造函数提供自己的实现.

如果您提供自己的线程安全集合,则可以使用所需的任何集合类型.这将允许您根据需要确定元素的优先级.

虽然没有可以实现所需功能的内置集合,但您可以将一对ConcurrentQueue<T>集合包装到实现的类中IProducerConsumerCollection<T>.这将允许您具有"高优先级"和"低优先级"元素.


Jar*_*Par 5

无法直接在a之上实现优先级队列BlockingCollection<T>.A BlockingCollection<T>最好被视为严格的队列,不能实现重新排序.

但是,您可以使用优先级队列和a的组合BlockingCollection<T>来实现相同的效果.让我们假设您实现了一个简单的PriorityQueue<T>正确下载您的下载.以下内容可用于为接收方的处理添加优先级

class DownloadManager {
  private PriorityQueue<Download> m_priorityQueue;
  private BlockingCollection<Download> m_downloadCollection;

  public bool TryGetNext(ref Download download) {
    PumpDownloadCollection();
    if (m_priorityQueue.IsEmpty) {
      download = null;
      return false;
    }

    download = m_priorityQueue.Dequeue();
    return true;
  }

  private void PumpDownloadCollection() {
    T value;
    while (m_downloadCollection.TryTake(out value)) {
      m_priorityQueue.Enqueue(value);
    }
  }
Run Code Online (Sandbox Code Playgroud)

注意:PriorityQueue<T>不是.Net Framework中实际存在的类型.根据下载项目的优先级安排,您需要自己编写.