我有一個下載隊列與BlockingCollection<>
實施。現在我想稍微優先考慮一下下載。我認爲將列表中的某些元素向上移動可能會很棒,就像在列表中一樣,但沒有像Remove()/ AddFirst()或Move()這樣的方法。元素順序BlockingCollection <>
在BlockingCollection<>
中安排物品的首選方式是什麼?
我有一個下載隊列與BlockingCollection<>
實施。現在我想稍微優先考慮一下下載。我認爲將列表中的某些元素向上移動可能會很棒,就像在列表中一樣,但沒有像Remove()/ AddFirst()或Move()這樣的方法。元素順序BlockingCollection <>
在BlockingCollection<>
中安排物品的首選方式是什麼?
BlockingCollection<T>
作品通過包裝內部IProducerConsumerCollection<T>
。缺省情況是在內部使用ConcurrentQueue<T>
,但可以通過this constructor提供自己的實現。
如果您提供了自己的線程安全集合,則可以使用任何您想要的集合類型。這將允許您根據需要優先考慮元素。
儘管沒有內置集合可以實現您所需的功能,但您可能會將一對ConcurrentQueue<T>
集合包裝到實現IProducerConsumerCollection<T>
的類中。這將允許您擁有「高優先級」和「低優先級」元素。
無法直接在BlockingCollection<T>
之上實施優先級隊列。 A BlockingCollection<T>
最好被視爲一個嚴格的隊列,無法實現重新排序。
但是,您可以使用優先級隊列和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);
}
}
注意的處理:PriorityQueue<T>
是不是實際上是在.Net框架中存在的類型。根據下載項目的優先級調度,您需要編寫自己的代碼。
不幸的是,沒有辦法以您想要的方式重新排列隊列。你真正需要的是作爲優先級隊列實現的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);
}
上面的例子會打印:
high1
high2
low1
low2
它迫使你使用多個隊列,所以它不是最完美的解決方案。
裏德在告訴你需要實施IProducerConsumerCollection<T>
時是正確的。但是,有一堂課可以幫助你。它不是內置的,但它的特色在MSDN。只需將此ConcurrentPriorityQueue
傳遞給您的BlockingCollection
即可。
這是我如何使用它:
private readonly BlockingCollection<KeyValuePair<int, ICommand>> _commands
= new BlockingCollection<KeyValuePair<int, ICommand>>(
new ConcurrentPriorityQueue<int, ICommand>());
的ICommand
是在我的項目的接口。
現在,這可以讓你添加項目是這樣的:
_actions.Add(new KeyValuePair<int, ICommand>(1, command1));
_actions.Add(new KeyValuePair<int, ICommand>(2, command2));
_actions.Add(new KeyValuePair<int, ICommand>(1, command3));
以較低的整數值作爲優先項目將首先執行。在上面的例子:
command1
command3
command2
當在你BlockingCollection
循環,您將不再獲得單個元素(在我的情況ICommand
),但KeyValuePair
。這當然可能需要一些代碼更改。一件好事是你有它的原始優先權:
foreach (var command in _queue)
{
var priority = command.Key;
var actualCommand = command.Value;
}