how to access the underlying default concurrent queue of a blocking collection

后端 未结 3 1244
广开言路
广开言路 2020-12-11 03:05

I have multiple producers and a single consumer. However if there is something in the queue that is not yet consumed a producer should not queue it again. (unique no duplica

3条回答
  •  囚心锁ツ
    2020-12-11 03:55

    In addition to the caveat Brian Gideon mentioned after Update, his solution suffers from these performance issues:

    • O(n) operations on the queue (queue.Contains(item)) have a severe impact on performance as the queue grows
    • locks limit concurrency (which he does mention)

    The following code improves on Brian's solution by

    • using a hash set to do O(1) lookups
    • combining 2 data structures from the System.Collections.Concurrent namespace

    N.B. As there is no ConcurrentHashSet, I'm using a ConcurrentDictionary, ignoring the values.

    In this rare case it is luckily possible to simply compose a more complex concurrent data structure out of multiple simpler ones, without adding locks. The order of operations on the 2 concurrent data structures is important here.

    public class NoDuplicatesConcurrentQueue : IProducerConsumerCollection
    {
        private readonly ConcurrentDictionary existingElements = new ConcurrentDictionary();
        private readonly ConcurrentQueue queue = new ConcurrentQueue();
    
        public bool TryAdd(T item)
        {
            if (existingElements.TryAdd(item, false))
            {
                queue.Enqueue(item);
                return true;
            }
            return false;
        }
    
        public bool TryTake(out T item)
        {
            if (queue.TryDequeue(out item))
            {
                bool _;
                existingElements.TryRemove(item, out _);
                return true;
            }
            return false;
        }
        ...
    }
    

    N.B. Another way at looking at this problem: You want a set that preserves the insertion order.

提交回复
热议问题