【问题标题】:Check for duplicates in Blocking collection [duplicate]检查阻塞集合中的重复项[重复]
【发布时间】:2016-03-02 20:33:46
【问题描述】:

在尝试添加新项目之前,检查“blockingcollection”中是否存在项目的最佳方法是什么?基本上我不希望将重复项添加到 BlockingCollection。

【问题讨论】:

    标签: c# .net


    【解决方案1】:

    您必须实现自己的 IProducerConsumerCollection<T>,其行为类似于集合(例如,不允许重复)。这是一个使用临界区 (C# lock) 使其线程安全的简单版本。对于高并发场景,您可以使用 SpinWait 之类的类来提高性能,方法与 ConcurrentQueue<T> 相同。

    public class ProducerConsumerSet<T> : IProducerConsumerCollection<T> {
    
      readonly object gate = new object();
    
      readonly Queue<T> queue = new Queue<T>();
    
      readonly HashSet<T> hashSet = new HashSet<T>();
    
      public void CopyTo(T[] array, int index) {
        if (array == null)
          throw new ArgumentNullException("array");
        if (index < 0)
          throw new ArgumentOutOfRangeException("index");
        lock (gate)
          queue.CopyTo(array, index);
      }
    
      public bool TryAdd(T item) {
        lock (gate) {
          if (hashSet.Contains(item))
            return false;
          queue.Enqueue(item);
          hashSet.Add(item);
          return true;
        }
      }
    
      public bool TryTake(out T item) {
        lock (gate) {
          if (queue.Count == 0) {
            item = default(T);
            return false;
          }
          item = queue.Dequeue();
          hashSet.Remove(item);
          return true;
        }
      }
    
      public T[] ToArray() {
        lock (gate)
          return queue.ToArray();
      }
    
      public void CopyTo(Array array, int index) {
        if (array == null)
          throw new ArgumentNullException("array");
        lock (gate)
          ((ICollection) queue).CopyTo(array, index);
      }
    
      public int Count {
        get { return queue.Count; }
      }
    
      public object SyncRoot {
        get { return gate; }
      }
    
      public bool IsSynchronized {
        get { return true; }
      }
    
      public IEnumerator<T> GetEnumerator() {
        List<T> list = null;
        lock (gate)
          list = queue.ToList();
        return list.GetEnumerator();
      }
    
      IEnumerator IEnumerable.GetEnumerator() {
        return GetEnumerator();
      }
    
    }
    

    如果需要,您可以详细说明此类以通过提供可选的 IEqualityComparer&lt;T&gt; 来自定义相等性,然后用于初始化 HashSet&lt;T&gt;

    当尝试插入重复项时,IProducerConsumerCollection&lt;T&gt;.Add 方法返回 false。这会导致BlockingCollection&lt;T&gt;.Add 方法抛出InvalidOperationException,因此您可能必须包装代码才能将项目添加到如下内容中:

    bool AddItem<T>(BlockingCollection<T> blockingCollection, T item) {
      try {
        blockingCollection.Add(item);
        return true;
      }
      catch (InvalidOperationException) {
        return false;
      }
    }
    

    请注意,如果您将项目添加到已完成的集合中,您还将收到 InvalidOperationException,并且您必须检查异常消息以确定异常的根本原因。

    【讨论】:

    • 我发现这种方法有一个问题,如果生产者添加了导致 InvalidOperationException 的重复项,阻塞集合不会达到上限
    【解决方案2】:

    使用TryAdd(data) 方法。您还可以传入timespan 对象或int 指示超时时间。返回truefalse。 请注意,如果基础集合类型无法处理重复项并且您尝试添加的数据是重复项,则会引发 InvalidOperationException

    【讨论】:

    • 所有底层 (IProdCons) 类都接受重复项,所以我认为这本身不会有帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-01-30
    • 1970-01-01
    • 2020-04-03
    • 1970-01-01
    • 2017-09-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多