我正在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
也有点慢。所以也许我需要其他收藏吗? 最佳答案
Keys.Max()
是杀手.。那是O(N)。如果这样做,则无需字典。
由于要添加和删除,因此无法增量计算最大值。因此,您最好使用为此创建的数据结构。通常是树木。我相信BCL具有SortedList
和SortedSet
和SortedDictionary
。其中之一是基于一棵快树。它具有最小和最大操作。
或者,将.NET集合库与优先级队列一起使用。
错误:添加就是活泼。您可能会覆盖非空集合。