【问题标题】:Correct way to guarantee thread safety when adding to a list using Parallel library使用并行库添加到列表时保证线程安全的正确方法
【发布时间】:2012-01-09 23:10:56
【问题描述】:

我遍历一个连接字符串数组,并在每个循环中提取一些信息并添加到列表中。现在,我想使用 Parallel 库使其成为多线程的,但我不确定该库是否保证写入列表是线程安全的,或者我是否需要使用锁定:

List<SomeType> list = new List<SomeType>();

settings.AsParallel().ForAll(setting => 
{
    list.AddRange(GetSomeArrayofSomeType(setting)); /// DO I NEED TO DO LOCKING HERE???
})

【问题讨论】:

  • 您为什么不首先避免这种复杂性,并预先选择要添加到list 的设置?
  • 我不向列表中添加设置,我为每个设置检索一些数组,并将该数组的内容添加到主列表中。检索可能是一个漫长的过程,因此我需要多线程

标签: c# multithreading thread-safety parallel-extensions


【解决方案1】:

写入列表对于多线程写入确实不安全。您需要使用lock 来同步访问或使用ConcurrentQueue 之类的集合,该集合专为多线程访问而设计。

锁定示例(假设list 是方法的本地)

List<SomeType> list = new List<SomeType>();
settings.AsParallel().ForAll(setting => { 
  lock (list) {
    list.AddRange(GetSomeArrayofSomeType(setting)); 
  }
});

或者更好的是使用SelectMany 而不是ForEach

var list = settings
  .AsParallel()
  .SelectMany(setting => GetSomeArrayOfSomeType(setting))
  .ToList();

【讨论】:

  • 让每个任务写入自己的列表也可以很好地工作(安全,因为只有一个线程查看每个列表),然后在最后一步将它们全部组合起来。这可以取胜,因为第一批添加需要零同步。
  • +1 对于 SelectMany,应避免 ForAll/lock 示例,因为它会在工作线程之间引入大量争用。
猜你喜欢
  • 2017-07-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-30
  • 2015-02-11
  • 1970-01-01
相关资源
最近更新 更多