c# - 检查阻塞集合中的重复项

标签 c# .net concurrency blockingcollection concurrent-collections

<分区>

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

最佳答案

您必须实现自己的 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<T> 详细说明此类以自定义相等性然后用于初始化 HashSet<T> .

IProducerConsumerCollection<T>.Add方法返回 false当试图插入重复项时。这导致 InvalidOperationExceptionBlockingCollection<T>.Add 抛出方法,因此您可能必须包装代码以将项目添加到如下所示的内容中:

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

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

关于c# - 检查阻塞集合中的重复项,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35745854/

相关文章:

C#,奇怪的优化

python - 防止在 GAE/memcache 上丢失更新/竞争条件的策略/模式

c# - 如何在最后一个列表中插入元素?

c# - 如何从基类中获取属性值?

c# - C# 安装应用程序中的 Google OAuth 2.0 身份验证

sql - SET NOCOUNT ON 使用情况

android - Coroutine Continuation 在内部是如何工作的?

c# - 在 Entity Framework 的动态 dbset 中使用 where 子句

c# - 如何在 C# 中将字符串转换为 "Null Terminated Byte Array"?

.net - 什么时候用 `let ... in`绑定(bind)变量?