是否有并发排序字典或类似的东西?

时间:2016-06-13 13:32:46

标签: c# concurrency sorteddictionary

对于我们一直在研究的项目,我们使用了并发字典,这很好,直到新的规范出现,需要对字典进行排序(它应该按照添加的顺序保留,有点像一个FIFO)。

这是我们目前的工作,我们从字典中取出x个数量(在这种情况下为5个)项目:

private Dictionary<PriorityOfMessage, ConcurrentDictionary<Guid, PriorityMessage>> mQueuedMessages = new Dictionary<PriorityOfMessage, ConcurrentDictionary<Guid, PriorityMessage>>();


var messages = new List<KeyValuePair<Guid, PriorityMessage>>();
messages.AddRange(mQueuedMessages[priority].Take(5));

然后我们用它做一些事情,最终如果一切顺利,我们就把它们删除了。

mQueuedMessages[priority].TryRemove(messageOfPriority.Key);

然而,如果事情失败,我们不会删除它们并稍后再尝试。所以不幸的是没有并发的排序字典,但是有没有办法确保消息按照添加的顺序保留?

非常重要的是我们可以从列表/字典中获取多个对象而不删除它们(或者我们需要能够将它们添加到前面)。

2 个答案:

答案 0 :(得分:3)

  

你每周多少次一次?

  

它可能是每秒一千次

每秒1000次锁定操作绝对没有。这几乎不会消耗任何时间。

  

我的同事已经尝试使用锁和列表,他认为它太慢了

这很可能意味着锁定区域太大了。我的猜测是这样的:

lock (...) {
 var item = TakeFromQueue();
 Process(item);
 DeleteFromQueue(item);
}

这不起作用,因为Process太慢了。必须是:

lock (...)
 var item = TakeFromQueue();

 Process(item);

lock (...)
 DeleteFromQueue(item);

根本不存在任何性能问题。

您现在可以选择您喜欢的任何数据结构。您不再受内置并发数据结构的功能约束。除了选择您喜欢的数据结构外,您还可以对其进行任何操作,例如以原子方式获取多个项目。

我还没有完全理解你的需求,但听起来SortedList可能会朝着正确的方向发展。

答案 1 :(得分:-1)

你也可以寻求另一种解决方案(避免在性能方面进行测试):

public class ConcurrentIndexableQueue<T> {
    private long tailIndex;
    private long headIndex;
    private readonly ConcurrentDictionary<long, T> dictionary;

    public ConcurrentIndexableQueue() {
        tailIndex = -1;
        headIndex = 0;
        dictionary = new ConcurrentDictionary<long, T>();
    }

    public long Count { get { return tailIndex - headIndex + 1; } }

    public bool IsEmpty { get { return Count == 0; } }

    public void Enqueue(T item) {
        var enqueuePosition = Interlocked.Increment(ref tailIndex);
        dictionary.AddOrUpdate(enqueuePosition, k => item, (k, v) => item);
    }

    public T Peek(long index) {
        T item;

        return dictionary.TryGetValue(index, out item) ? 
            item : 
            default(T);
    }

    public long TryDequeue(out T item) {
        if (headIndex > tailIndex) {
            item = default(T);
            return -1;
        }

        var dequeuePosition = Interlocked.Increment(ref headIndex) - 1;

        dictionary.TryRemove(dequeuePosition, out item);

        return dequeuePosition;
    }

    public List<T> GetSnapshot() {
        List<T> snapshot = new List<T>();
        long snapshotTail = tailIndex;
        long snapshotHead = headIndex;

        for (long i = snapshotHead; i < snapshotTail; i++) {
            T item;

            if (TryDequeue(out item) >= 0) {
                snapshot.Add(item);
            }
        }

        return snapshot;
    }
}