安全地附加到Parallel.ForEach中的列表

时间:2013-05-28 18:32:26

标签: c# collections thread-safety task-parallel-library plinq

我有以下代码

var myResponse = new Response();
Parallel
.ForEach(itemsListDto
         , new ParallelOptions { MaxDegreeOfParallelism = 10 }
         , itemDto => {
                         var tResponse = _itemService
                                         .InsertItem
                                            (itemDto
                                             , new RequestMessage 
                                                   {UserName = RequestUserName});
                          myResponse.AddErrors(tResponse.Errors);
                       }
         );
return myResponse;

似乎myResponse没有添加所有Errors。我应该如何重写这个以确保安全?

1 个答案:

答案 0 :(得分:4)

您需要同步myResponse的访问权限,因为它听起来像AddErrors方法不是线程安全的:

var myResponse = new Response();
var syncObj = new object();
Parallel.ForEach(itemsListDto, new ParallelOptions { MaxDegreeOfParallelism = 10 }, itemDto =>
    {
        var tResponse = _itemService.InsertItem(itemDto, new RequestMessage {UserName = RequestUserName});
        lock(syncObj)
            myResponse.AddErrors(tResponse.Errors);
    });
return myResponse;

如果InsertItem是一个相当漫长的过程,那么就性能而言这是可以接受的。

如果InsertItem是一种相当快的方法,这可能会增加大量的同步开销,并导致总体时间接近同步循环。在这种情况下,您可能会使用Parallel.ForEach which provide local state的重载来减少锁定频率,并将错误存储在本地状态,然后在完整循环结束时进行聚合。我有一篇文章详细描述process required to aggregate data efficiently using Parallel.ForEach