简体   繁体   English

我如何在C#中实现QueueDictionary,Queue和Dictionary的组合?

[英]How would I implement a QueueDictionary, a combination of Queue and Dictionary in C#?

Basically the data structure I want would mirror a MSMQ but would be in memory, because it is being used in the one process. 基本上我想要的数据结构将镜像MSMQ,但会在内存中,因为它在一个进程中使用。 By mirroring MSMQ I mean you would enqueue objects, then you could either dequeue objects or retrieve them using a key. 通过镜像MSMQ,我的意思是你会将对象排队,然后你可以将对象出列或使用密钥检索它们。 Here is me initial attempt. 这是我最初的尝试。 My main problem with this attempt is that the Get by id would be used frequently and therefore the queue would end up having a lot of "dead" objects in it. 这个尝试的主要问题是Get by id会频繁使用,因此队列最终会有很多“死”对象。

public class QueueDictionary<TKey, TValue>
{
    private readonly Queue _queue = new Queue();
    private readonly Dictionary<TKey, TValue> _dictionary = new Dictionary<TKey, TValue>();
    private readonly object _syncRoot = new object();

    public TValue Dequeue()
    {
        lock (_syncRoot)
        {
            TKey key = (TKey)_queue.Dequeue();
            while (!_dictionary.ContainsKey(key))
                key = (TKey)_queue.Dequeue();
            return _dictionary[key];
        }
    }

    public TValue Get(TKey key)
    {
        lock (_syncRoot)
        {
            TValue result = _dictionary[key];
            _dictionary.Remove(key);
            return result;
        }
    }

    public void Enqueue(TKey key, TValue value)
    {
        lock (_syncRoot)
        {
            _dictionary.Add(key, value);
            _queue.Enqueue(key);
        }
    }
}

Rather than using a Queue internally, you could use a LinkedList. 您可以使用LinkedList,而不是在内部使用Queue。 Then in the Dictionary you can store the Key and the LinkedListNode. 然后在Dictionary中,您可以存储Key和LinkedListNode。 Then when you remove the item from the Dictionary, you can unlink the LinkedListNode from the linked list. 然后,当您从字典中删除该项时,您可以取消链接列表中的LinkedListNode链接。 Of course you loose the locality of the Queue, but gain the performance of the random access. 当然,你放弃了队列的局部性,但获得了随机访问的性能。

Here is a quick and dirty example, not tested so excuse any errors and no error checking. 这是一个快速而肮脏的例子,没有经过测试,因此可以解释任何错误和错误检查。 For example you should check if the queue is empty, make sure an item with the same key is not already in the dictionary etc. 例如,您应检查队列是否为空,确保具有相同键的项目尚未在字典中等。

public class QueueDictionary<TKey, TValue>
{
  private readonly LinkedList<Tuple<TKey, TValue>> _queue =
    new LinkedList<Tuple<TKey, TValue>>();

  private readonly Dictionary<TKey, LinkedListNode<Tuple<TKey, TValue>>> 
    _dictionary = new Dictionary<TKey, LinkedListNode<Tuple<TKey, TValue>>>();

  private readonly object _syncRoot = new object();

  public TValue Dequeue()
  {
    lock (_syncRoot)
    {
      Tuple<TKey, TValue> item = _queue.First();
      _queue.RemoveFirst();
      _dictionary.Remove(item.Item1);
      return item.Item2;
    }
  }

  public TValue Dequeue(TKey key)
  {
    lock (_syncRoot)
    {
      LinkedListNode<Tuple<TKey, TValue>> node = _dictionary[key];
      _dictionary.Remove(key);
      _queue.Remove(node);
      return node.Value.Item2;
    }
  }

  public void Enqueue(TKey key, TValue value)
  {
    lock (_syncRoot)
    {
      LinkedListNode<Tuple<TKey, TValue>> node = 
        _queue.AddLast(new Tuple<TKey, TValue>(key, value));
      _dictionary.Add(key, node);
    }
  }
}

Well your object can act like a queue without actually using the Queue class as its internal storage. 那么你的对象可以队列实际上并没有使用Queue类作为它的内部存储。 Depending on how many items you plan on keeping, it might be easier just to maintain a single LinkedList(T) instead of storing the item in both a LinkedList(T) and a Dictionary(K,V). 根据您计划保留的项目数量,可能更容易维护单个LinkedList(T),而不是将项目存储在LinkedList(T)和Dictionary(K,V)中。

But basically, instead of using a Queue internally, you could use a LinkedList(T) and just add new items to the end of the list and dequeue from the front of the list. 但基本上,您可以使用LinkedList(T)而不是在内部使用Queue,只需将新项添加到列表的末尾,然后从列表的前面出列。 When you need to find one by key, you can just scan the list for the matching key or if the number of items makes this perform poorly, you could double up your storage with a Dictionary(K, LinkedListNode(T)) and use the dictionary for your key lookups. 当你需要通过键找到一个时,你可以只扫描列表中的匹配键,或者如果项目数量使这个表现不佳,你可以用一个字典(K,LinkedListNode(T))加倍你的存储并使用密钥查找的字典。

What if you used a double-linked list to act as the Queue and that way you can have full control of the Enqueue, Dequeue, and specially the Get method. 如果您使用双链表作为队列,那么您可以完全控制Enqueue,Dequeue,特别是Get方法。 So in the Get method you can simply remove the key from the double-linked list. 因此,在Get方法中,您只需从双链表中删除键即可。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM