[英]Concurrent Collection with fastest possible Add, Remove and Find the highest
我正在C#.NET中進行一些繁重的計算,當並行執行這些計算時。for循環必須在收集中收集一些數據,但是由於內存有限,我無法收集所有結果,因此我只存儲最佳結果。
這些計算必須盡可能快,因為它們已經花費了太多時間。 因此,經過大量優化之后,我發現最慢的是我的ConcurrentDictionary
集合。 我想知道是否應該切換到具有更快的添加,刪除和查找最高值(可能是排序的集合)的功能,並只對我的主要操作使用鎖,或者我可以使用ConcurrentColletion
來做一些好事並加快速度。
這是我的實際代碼,由於此巨大的鎖定,我知道它很糟糕,但是如果沒有它,我似乎會失去一致性,並且很多刪除嘗試都失敗了。
public class SignalsMultiValueConcurrentDictionary : ConcurrentDictionary<double, ConcurrentBag<Signal>>
{
public int Limit { get; set; }
public double WorstError { get; private set; }
public SignalsDictionaryState TryAddSignal(double key, Signal signal, out Signal removed)
{
SignalsDictionaryState state;
removed = null;
if (this.Count >= Limit && signal.AbsoluteError > WorstError)
return SignalsDictionaryState.NoAddedNoRemoved;
lock (this)
{
if (this.Count >= Limit)
{
ConcurrentBag<Signal> signals;
if (TryRemove(WorstError, out signals))
{
removed = signals.FirstOrDefault();
state = SignalsDictionaryState.AddedAndRemoved;
}
else
state = SignalsDictionaryState.AddedFailedRemoved;
}
else
state = SignalsDictionaryState.AddedNoRemoved;
this.Add(key, signal);
WorstError = Keys.Max();
}
return state;
}
private void Add(double key, Signal value)
{
ConcurrentBag<Signal> values;
if (!TryGetValue(key, out values))
{
values = new ConcurrentBag<Signal>();
this[key] = values;
}
values.Add(value);
}
}
另請注意,因為我使用信號的絕對誤差,所以有時(應該非常少見)我在一個鍵上存儲多個值。
我的計算中使用的唯一操作是TryAddSignal
因為它可以執行我想要的操作->如果我的信號集超過限制,那么它將刪除具有最高錯誤的信號並添加新信號。
由於我在計算開始時就設置了Limit
屬性,因此不需要可調整大小的集合。
這里的主要問題是,即使沒有那么大的鎖, Keys.Max
也會有點太慢。 所以也許我需要其他收藏嗎?
大lock
語句至少是可疑的。 如果您說Keys.Max()
較慢, Keys.Max()
簡單的改進是遞增地計算最大值。 僅在刪除密鑰后才需要刷新它:
//...
if (TryRemove(WorstError, out signals))
{
WorstError = Keys.Max();
//...
WorstError = Math.Max(WorstError, key);
Keys.Max()
是殺手.。 那是O(N)。 如果這樣做,則無需字典。
由於要添加和刪除,因此無法增量計算最大值。 因此,您最好使用為此創建的數據結構。 通常是樹木。 我相信BCL具有SortedList
和SortedSet
和SortedDictionary
。 其中之一是基於一棵快樹。 它具有最小和最大操作。
或者,將.NET集合庫與優先級隊列一起使用。
錯誤:添加就是活潑。 您可能會覆蓋非空集合。
最后,我要做的是按照@usr的建議,基於二叉樹實現Heap。 我的最終集合不是並發的,而是同步的(我使用了鎖)。 我檢查了性能思想,並很快完成了工作。 這是偽代碼:
public class SynchronizedCollectionWithMaxOnTop
{
double Max => _items[0].AbsoluteError;
public ItemChangeState TryAdd(Item item, out Item removed)
{
ItemChangeState state;
removed = null;
if (_items.Count >= Limit && signal.AbsoluteError > Max)
return ItemChangeState.NoAddedNoRemoved;
lock (this)
{
if (_items.Count >= Limit)
{
removed = Remove();
state = ItemChangeState.AddedAndRemoved;
}
else
state = ItemChangeState.AddedNoRemoved;
Insert(item);
}
return state;
}
private void Insert(Item item)
{
_items.Add(item);
HeapifyUp(_items.Count - 1);
}
private void Remove()
{
var result = new Item(_items[0]);
var lastIndex = _items.Count - 1;
_items[0] = _items[lastIndex];
_items.RemoveAt(lastIndex);
HeapifyDown(0);
return result;
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.