具有多线程的 LINQ 查询
本文关键字:LINQ 查询 多线程 | 更新日期: 2023-09-27 18:35:04
我有一个多线程应用程序,其中多个线程操作列表(T),添加,删除和查询列表。在这里,其中一个线程查询列表,然后需要迭代结果集。当然,预计会出现异常,指示集合在迭代期间发生了更改,出于某种原因,查询的性质和迭代行为我无法在此处锁定列表,因此我尝试使用 .ToList() 函数,但奇怪的是我仍然收到相同的错误。我以为。ToList() 函数获取结果的单独列表,但它看起来不是。是否有其他方法可以在新列表中获取查询结果?
如果不进行
同步,则无法从多个线程访问List<T>
实例,因为生成的行为未定义,并且在大多数情况下会导致问题。你已经找到了一个。
创建某种ConcurrentCollection
并同步您需要的所有操作:
public class ConcurrentCollection<T> : IEnumerable<T>
{
private readonly List<T> innerList = new List<T>();
public void Add(T item)
{
lock (innerList)
{
innerList.Add(item);
}
}
public bool TryRemove(T item)
{
lock (innerList)
{
return innerList.Remove(item);
}
}
public int Count
{
get
{
lock (innerList)
{
return this.innerList.Count;
}
}
}
public IEnumerator<T> GetEnumerator()
{
lock (innerList)
{
return (IEnumerator<T>) this.innerList.ToArray().GetEnumerator();
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
这里的关键点是返回的枚举器枚举列表的快照(ToArray
),因此是否在两者之间修改它并不重要。
请记住,您必须为调用代码创建"原子"操作。假设仅当列表为空时,您才想从一个线程中添加项目。这是错误的:
if (collection.Count == 0)
{
collection.Add(item);
}
相反,将另一个成员添加到ConcurrentCollection
...
public bool AddIfEmpty(T item)
{
lock (innerList)
{
if (innerList.Count == 0)
{
innerList.Add(item);
return true;
}
return false;
}
}
。并像这样使用它:
var itemWasAdded = collection.AddIfEmpty(item);