具有多线程的 LINQ 查询

本文关键字:LINQ 查询 多线程 | 更新日期: 2023-09-27 18:35:04

我有一个多线程应用程序,其中多个线程操作列表(T),添加,删除和查询列表。在这里,其中一个线程查询列表,然后需要迭代结果集。当然,预计会出现异常,指示集合在迭代期间发生了更改,出于某种原因,查询的性质和迭代行为我无法在此处锁定列表,因此我尝试使用 .ToList() 函数,但奇怪的是我仍然收到相同的错误。我以为。ToList() 函数获取结果的单独列表,但它看起来不是。是否有其他方法可以在新列表中获取查询结果?

具有多线程的 LINQ 查询

如果不进行

同步,则无法从多个线程访问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);