【问题标题】:How to add item to dictionary "Parallel loop safe"如何将项目添加到字典“并行循环安全”
【发布时间】:2014-05-12 11:59:43
【问题描述】:

我有一个 Parallel.ForEach 循环做一些处理。但是第一个操作是在不包含键的情况下在字典中添加一个值。添加它时出现错误,它说密钥已经在字典中。我猜想密钥是在 .Contains 检查这个线程之后由并行进程添加的,但在添加之前。除了将该行放在 try-catch 中之外,还有其他简单的解决方案可以用来防止该错误吗?

Parallel.ForEach(branchFixes, b =>
{
  Parallel.ForEach(b.Value, t =>
  {
    var team = t.Key;
    if (!resultTeamDict.ContainsKey(team))
    {
      resultTeamDict.Add(team, new Dictionary<FixItem, Dictionary<BranchInfo, bool>>());
    }
  });
});

【问题讨论】:

  • @mellamokb:这不是真的——如果你有多个内核可用,你为什么不想使用它们呢?它只有在问题自然可并行的情况下才有效,但“CPU 密集型”意味着“并行变慢”的想法是无稽之谈。
  • @JonSkeet:是的,你是对的。我在考虑单核。

标签: c# dictionary parallel.foreach


【解决方案1】:

即使除了你的竞争条件,Dictionary&lt;,&gt; 也不是线程安全的。您应该使用ConcurrentDictionary&lt;,&gt;,在这种情况下可能使用AddOrUpdate 方法来原子地执行修改。 (我假设您也想为“嵌套”字典添加一个值。否则,请考虑 TryAdd。)

【讨论】:

    【解决方案2】:

    您可以使用 .NET 4.5 中的 ConcurrentDictionary 并将 ContainsKey 和 Add 方法调用替换为 TryAdd。见http://msdn.microsoft.com/en-us/library/dd287191(v=vs.110).aspx

    【讨论】:

    • ConcurrentDictionary 是在 .NET 4.0 中引入的。
    【解决方案3】:

    这是“检查时间到使用时间”错误的教科书示例:在检查字典是否包含密钥和 Add 调用之间,另一个线程可能已经插入了该项目,从而使Add的前置条件。

    解决方案是使用ConcurrentDictionary&lt;T&gt; 或通过锁或其他同步工具相互排除线程同时更新字典。

    您可能想要分析您的代码以检查是否值得触发线程——在这种情况下开销可能非常高。

    【讨论】:

      【解决方案4】:

      我看到了一些关于 ConcurrentDictionary 的建议。 请注意优化和性能问题。 Dictionary 和 ConcurrentDictionary RunTime Complexity 在插入和读取数据方面存在差异(使用 ConcurrentDictionary 可能会慢 10 倍)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-03-27
        • 1970-01-01
        相关资源
        最近更新 更多