1

这是一个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 中不明显的原因,无法做到这一点。

编辑

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

4

4 回答 4

4

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

附带说明:

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

将使这更有效率。减少增长也意味着减少对lock.

于 2012-05-01T07:16:23.303 回答
3

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

查看Parallel For Loop - 添加到列表时的问题以获取更多信息

于 2012-05-01T07:12:57.853 回答
2

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

ConcurrentBag<int> bag=new ConcurrentBag<int>();
ParallelEnumerable.Range(0,10000).ForAll(s => {if(MyFunc(s)) bag.Add(s);});
于 2012-05-01T08:25:40.980 回答
0

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

于 2012-05-01T07:21:18.927 回答