【问题标题】:Safely appending to a list in a Parallel.ForEach安全地附加到 Parallel.ForEach 中的列表
【发布时间】:2013-05-28 18:32:25
【问题描述】:

我有以下代码

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 添加到其中。我应该如何重写它以确保安全?

【问题讨论】:

  • 请贴出AddErrors的定义。

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


【解决方案1】:

您需要同步对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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-12-13
    • 1970-01-01
    • 1970-01-01
    • 2018-10-12
    • 2019-09-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多