.net 检查阻塞集合中的重复项[duplicate]

y1aodyip  于 2023-02-10  发布在  .NET
关注(0)|答案(2)|浏览(114)
    • 此问题在此处已有答案**:

Concurrent collections and unique elements(2个答案)
How to access the underlying default concurrent queue of a blocking collection?(4个答案)
六年前关闭了。
在尝试添加一个新项目之前,检查BlockingCollection中是否存在一个项目的最佳方法是什么?基本上,我不希望重复的项目添加到BlockingCollection中。

mqkwyuun

mqkwyuun1#

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

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<T>(然后用于初始化HashSet<T>)来详细说明此类以自定义相等性。
IProducerConsumerCollection<T>.Add方法在试图插入重复项时返回false,这将导致BlockingCollection<T>.Add方法抛出InvalidOperationException,因此您可能需要将代码打包,以便将项添加到如下内容中:

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

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

wa7juj8i

wa7juj8i2#

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

相关问题