在.Net字典中,索引超出数组界限的替代原因

10

我了解字典对象索引超出范围错误的主要原因之一是线程冲突(同时读写同一个字典)。但是,我遇到了一个令人困惑的情况,线程冲突并不能充分解释这个问题。

以下是具体情况: 我编写的代码在多线程处理时以不安全的方式实现了字典。 这段代码已经作为Web服务实现于两个服务器上,分别是Server A和Server B。这些服务器通过负载均衡器进行访问,将按照轮询方式发送请求到A和B服务器。

现在来说说进入棘手的部分。错误仅在Server A上显示,而在Server B上从未出现过。根据我们的硬件团队,这两个服务器是完全相同的。虽然线程冲突本质上是一个随机过程,但它应该会平等地影响我的两个服务器。我在一个服务器上看到了50多个错误实例,而在另一个服务器上则没有。统计学上认为,线程冲突只在一个服务器上发生而另一个服务器则没有出现错误的概率很小。

我已经修改了应用程序,使其更加线程安全,但是在字典对象的插入操作中,还有哪些其他原因可能导致此错误的出现?


你确定负载均衡器将请求发送到B服务器吗?可能只会影响第一台服务器。 - petro.sidlovskyy
也许一个服务器使用32位操作系统,另一个使用64位? - Roman Starkov
@petro.sidlovskyy 我已经确认根据日志文件,两个服务器都有流量。 - Joshua
你能升级到 .Net 4 并使用 ConcurrentDictionary 吗? - Gabe
@Gabe 升级到 .Net 4 不可能。 - Joshua
3个回答

7
尽管线程冲突本质上是一个随机过程,但实际上它严重依赖时间,而时间可以是可重复的。系统往往会趋于特定的模式。像微软研究的CHESS这样的线程竞赛诊断工具通过向线程执行注入随机延迟来发挥作用,以使系统跳出这种模式。虽然系统偶尔会自行跳出这种模式,但每周只会发生一次左右。那是随机的,只是不够随机,无法帮助您调试问题。
因此,看到一个服务器失败而另一个服务器没有失败并不意味着什么。负载均衡器可能与之有关。您将永远无法找出确切的原因,因为您无法了解那50次中发生了什么。这还不够。

1

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

我只是在想,假设您连接到服务器B的网络延迟比服务器A要稍高一些。这可能会在该服务器上为客户端请求提供足够的距离,导致字典访问,从而使您可以使用不严格安全的多线程代码。

如果请求到达Server A更快,这可能会导致超出范围的错误。

像我说的,这可能很牵强——只是一个想法。我觉得抛出这个想法也无妨。


0

我无法解释为什么它在一个服务器上不起作用,而在另一个服务器上可以。然而,您的问题是多线程问题。

正如您可能已经注意到的那样,在多线程环境中,这将无法工作:

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/


这并不应该让你感到惊讶,因为它们在第一种情况下并不是线程安全的集合? - Kurru

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接