Альтернативные причины для индекса были за пределами массива в словаре .Net - PullRequest
10 голосов
/ 12 января 2011

Я понимаю, что одной из основных причин, по которой Index выходит за границы ошибки для объекта Dictionary, является конфликт потоков.(Чтение и запись в один и тот же словарь в одно и то же время) Однако я столкнулся с удивительным случаем, когда коллизия потоков не является достаточным объяснением.

Вот ситуация: я написал код, который небезопасно реализует Словарь для многопоточной обработки.

Код был реализован в виде веб-службы на двух серверах, сервере А,и сервер B. Доступ к серверам осуществляется через балансировщик нагрузки, который будет отправлять запросы на серверы A и B циклическим образом.

Теперь вот сложная часть.Ошибка отображается ТОЛЬКО на сервере А, а не на сервере В. По мнению нашей команды аппаратного обеспечения, оба сервера идентичны.Хотя коллизия потоков по своей природе является случайным процессом, она все равно должна одинаково влиять на оба моих сервера.Я вижу 50+ случаев ошибки на одном сервере и 0 на другом.Статистически маловероятно, что конфликты потоков происходят только на одном из моих серверов, в то время как другой работает без ошибок.

Я уже изменяю приложение, чтобы сделать его более безопасным для работы с потоками, но какие еще могут быть причины для этой ошибки, возникающей при выполнении операции вставки объекта Dictionary?

Ответы [ 3 ]

7 голосов
/ 13 января 2011

Хотя коллизия потоков является по своей природе случайным процессом

Совсем нет.Это критически зависит от времени.И время может быть повторяемым, системы, как правило, устанавливаются в определенные модели.Инструмент диагностики гонки потоков, такой как CHESS от Microsoft Research, работает путем введения случайных задержек в выполнение потока.Чтобы система выпала из такой схемы.Как это иногда бывает само собой, но только раз в неделю или около того. То, что является случайным, просто не настолько случайным, чтобы дать вам шанс отладить проблему.

Таким образом, сбой одного сервера, а не другого ничего не значит.Балансировщик нагрузки, вероятно, как-то связан с этим.Вы просто никогда не сможете выяснить точную причину, потому что вы не можете выяснить, что произошло эти 50 раз.Этого недостаточно.

1 голос
/ 12 января 2011

Это, вероятно, надуманно, но знаете ли вы, что ваши соединения с двумя серверами через балансировщик нагрузки равны? (Я действительно ничего не знаю о том, как работает балансировка нагрузки, так что это может быть глупой мыслью с самого начала.)

Я просто думаю, скажем, у вас немного больше задержки в сети при подключении к серверу B, чем к серверу A. Это может обеспечить достаточное расстояние между запросами клиентов на этом сервере, что приведет к доступу к словарю, что позволит вам избежать проблем с многопоточностью код, который не является строго говоря, безопасным.

Если запросы доходят до сервера А немного быстрее, это может изменить ситуацию к ошибкам вне диапазона.

Как я уже сказал, вероятно, надуманно - просто идея. Я подумал, что это не помешает выбросить это там.

0 голосов
/ 12 января 2011

Я не могу объяснить, почему это не работает на одном сервере, но не на другом.Однако у вас проблемы с многопоточностью.

Как вы могли заметить, в многопоточной среде это не будет работать:

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/

...