您的实现是正确的。不幸的是,.NET Framework没有提供内置的并发哈希集类型,但是有一些解决方法。
ConcurrentDictionary(推荐)
第一个解决方法是使用命名空间为 System.Collections.Concurrent
的类ConcurrentDictionary<TKey, TValue>
。在这种情况下,值是无意义的,因此我们可以使用简单的 byte
(1个字节在内存中)。
private ConcurrentDictionary<string, byte> _data
这是推荐的选项,因为该类型是线程安全的,并且提供了与
HashSet<T>
相同的优点,除了键和值是不同的对象。
来源:
Social MSDN
自我实现
最后,您可以像您所做的那样,使用锁或其他.NET提供的方式来实现自己的数据类型以实现线程安全。这里有一个很好的例子:
如何在.Net中实现ConcurrentHashSet
这种解决方案唯一的缺点是,即使是读取操作,类型
HashSet<T>
也没有官方的并发访问支持。
我引用链接帖子的代码(最初由
Ben Mosher编写)。
using System;
using System.Collections.Generic;
using System.Threading;
namespace BlahBlah.Utilities
{
public class ConcurrentHashSet<T> : IDisposable
{
private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
private readonly HashSet<T> _hashSet = new HashSet<T>();
#region Implementation of ICollection<T> ...ish
public bool Add(T item)
{
_lock.EnterWriteLock();
try
{
return _hashSet.Add(item);
}
finally
{
if (_lock.IsWriteLockHeld) _lock.ExitWriteLock();
}
}
public void Clear()
{
_lock.EnterWriteLock();
try
{
_hashSet.Clear();
}
finally
{
if (_lock.IsWriteLockHeld) _lock.ExitWriteLock();
}
}
public bool Contains(T item)
{
_lock.EnterReadLock();
try
{
return _hashSet.Contains(item);
}
finally
{
if (_lock.IsReadLockHeld) _lock.ExitReadLock();
}
}
public bool Remove(T item)
{
_lock.EnterWriteLock();
try
{
return _hashSet.Remove(item);
}
finally
{
if (_lock.IsWriteLockHeld) _lock.ExitWriteLock();
}
}
public int Count
{
get
{
_lock.EnterReadLock();
try
{
return _hashSet.Count;
}
finally
{
if (_lock.IsReadLockHeld) _lock.ExitReadLock();
}
}
}
#endregion
#region Dispose
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
if (_lock != null)
_lock.Dispose();
}
~ConcurrentHashSet()
{
Dispose(false);
}
#endregion
}
}
编辑: 将进入锁方法移至try
块外部, 因为它们可能会抛出异常并执行finally
块中包含的指令。
ConcurrentBag (不建议使用)
不建议使用ConcurrentBag<T>
,因为该类型只允许以线程安全的方式插入一个给定元素并从集合中删除一个随机元素。这个类是设计用于促进生产者和消费者场景,这不是 OP 所追求的(更多解释请参见此处)。
其他操作(例如扩展方法提供的)不支持并发使用。MSDN 文档警告: "ConcurrentBag 的所有公共和受保护成员都是线程安全的,并且可以从多个线程同时使用。但是,通过 ConcurrentBag 实现的接口之一访问的成员(包括扩展方法)不保证是线程安全的,可能需要由调用方同步。"
ReaderWriterLock
将非常有用(高效)。我们需要知道是否对 OP 适用此情况。 - Sriram Sakthivel