簡體   English   中英

並發收集,並盡可能快地添加,刪除和查找最高的

[英]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具有SortedListSortedSetSortedDictionary 其中之一是基於一棵快樹。 它具有最小和最大操作。

或者,將.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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM