我正在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具有SortedListSortedSetSortedDictionary。其中之一是基于一棵快树。它具有最小和最大操作。

或者,将.NET集合库与优先级队列一起使用。

错误:添加就是活泼。您可能会覆盖非空集合。

10-08 01:18