如果我不打算在添加元素时从列表中读取,是否有必要在向 C# 列表添加元素之前锁定 C# 列表

本文关键字:列表 元素 添加 锁定 是否 读取 如果 | 更新日期: 2023-09-27 18:32:44

这是一个MWE:

Func<Int32, Boolean> MyFunc = (s) => {
    var res = false;
    // Insert function logic to modify the value to res
    return res;
};
var Result = new List<Int32> ();
var LockObj = new Object ();
ParallelEnumerable.Range (1, 100000)
    .ForAll (s => {
        if (MyFunc (s)) {
            lock (LockObj) { // IS THIS NECESSARY?
                Result.Add (s);
            } // End lock
        }
    });

这就是情况的归结。 如果我不打算在 ParallelEnumerable 语句完成执行之前查询它,我认为我不需要锁定 Result 是否正确?

请注意:我知道 MWE 最好通过"Where"子句来解决,如下所示:

ParallelEnumerable.Range (1, 100000)
    .Where (s => MyFunc (s));

但由于MWE中不明显的原因,这是不可能的。

编辑

感谢所有回答的人。 也感谢您的评论。 我已经纠正了董发现的错误。

如果我不打算在添加元素时从列表中读取,是否有必要在向 C# 列表添加元素之前锁定 C# 列表

是的,你必须lock .并行 将导致并发调用Add()

附带说明一下:

//var Result = new List<Int32> ();
var Result = new List<Int32> (100000);
ParallelEnumerable.Range (1, 100000)

将使这更有效率。更少的增长也意味着更少的lock竞争。

添加到泛型列表不是线程安全的。锁定是一种可能性。您还可以使用 im .Net 4.0 引入的线程安全集合类型之一

查看并行 for 循环 - 添加到列表时的问题以获取更多信息

可以通过选择现有的并行集合之一来消除大量争用:

ConcurrentBag<int> bag=new ConcurrentBag<int>();
ParallelEnumerable.Range(0,10000).ForAll(s => {if(MyFunc(s)) bag.Add(s);});

使用 Semaphore.it 将管理对共享资源的访问(在您的情况下为通用列表)。