【问题标题】:Alternative causes for Index was outside the bounds of the array in .Net dictionaryIndex 的替代原因超出了 .Net 字典中的数组范围
【发布时间】:2011-06-08 02:34:21
【问题描述】:

我了解 Dictionary 对象的 Index outside the bounds 错误的主要原因之一是线程冲突。 (同时读取和写入同一个字典)但是,我遇到了一个令人困惑的情况,即线程冲突不足以解释。

情况如下: 我编写的代码以不安全的方式实现 Dictionary 以进行多线程处理。

代码已作为 Web 服务实现到两台服务器(服务器 A 和服务器 B)上。通过负载平衡器访问服务器,负载平衡器将以循环方式向服务器 A 和 B 发送请求。

现在是棘手的部分。该错误仅显示在服务器 A 上,而从未出现在服务器 B 上。根据我们的硬件团队的说法,两台服务器是相同的。尽管线程冲突本质上是一个随机过程,但它仍然应该同样影响我的两个服务器。我在一台服务器上看到 50 多个错误实例,在另一台服务器上看到 0 个。从统计上看,线程冲突仅发生在我的一台服务器上,而另一台服务器运行时没有错误是不太可能的。

我已经在修改应用程序以使其线程更安全,但是在 Dictionary 对象的插入操作中,还有什么其他原因会引发此错误?

【问题讨论】:

  • 您确定负载均衡器向服务器 B 发送请求吗?可能它只影响第一台服务器。
  • 也许一台服务器有 32 位操作系统而另一台有 64 位?
  • @petro.sidlovskyy 我已经确认两台服务器都有基于日志文件的流量
  • 你能升级到 .Net 4 并使用ConcurrentDictionary吗?
  • @Gabe 无法升级到 .Net 4

标签: c# .net dictionary


【解决方案1】:

虽然线程冲突本质上是一个随机过程

一点也不。它严重依赖于时机。而且时间可以重复,系统倾向于适应特定的模式。像 Microsoft Research 的 CHESS 这样的线程竞争诊断工具通过将随机延迟注入线程的执行来工作。让系统摆脱这种模式。就像它偶尔会自己做的那样,但每周只有一次左右。 是随机的,只是随机性不足以让您尝试调试问题。

因此,看到一台服务器出现故障而不是另一台出现故障并没有任何意义。负载均衡器可能与它有关。你永远无法找出确切的原因,因为你无法找出这 50 次发生了什么。这还不够。

【讨论】:

    【解决方案2】:

    这可能有点牵强,但是您是否碰巧知道您通过负载平衡器到两台服务器的连接 是否相等? (我对负载平衡的工作原理一无所知,所以从一开始这可能是一个愚蠢的想法。)

    我只是在想,假设您与服务器 B 的连接比服务器 A 的网络延迟稍长。这可以在该服务器上的客户端请求之间提供足够的距离,从而导致字典访问,让您摆脱多线程严格来说不安全的代码。

    如果请求到达服务器 A 的速度稍微快一点,这可能会产生超出范围的错误。

    就像我说的那样,可能有点牵强——只是一个想法。我认为把它扔在那里不会有什么坏处。

    【讨论】:

      【解决方案3】:

      我无法解释为什么它不能在一台服务器上运行,而在另一台服务器上却不行。但是,您的问题是多线程问题。

      您可能已经注意到,这在多线程环境中不起作用:

      if (!dict.ContainsKey("myKey"))
          dict.Add("myKey", value);
      

      同样适用:

      if (dict.ContainsKey("myKey"))
          return dict["myKey"];
      

      您可能会感到惊讶的是 TryGetValue 也不是线程安全的:

      MyObject obj;
      return dict.TryGetValue("myKey", out obj) ? obj : null;
      

      参考:http://www.grumpydev.com/2010/02/25/thread-safe-dictionarytkeytvalue/

      【讨论】:

      • 这不应该让你感到惊讶,因为在第一种情况下它们不是线程安全的集合?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多