У нас есть приложение, которое генерирует смоделированные данные для одного из наших сервисов в целях тестирования. Каждый элемент данных имеет уникальный Guid. Однако, когда мы запускали тест после некоторых незначительных изменений кода симулятора, все созданные им объекты имели одинаковый Guid.
Был создан единственный объект данных, затем цикл for, в котором были изменены свойства объекта, включая новый уникальный Guid, и он был отправлен в службу через удаленное взаимодействие (сериализуемый, а не маршалинг по ссылке, если это то, что вы думаешь), зацикливайся и делай еще раз и т. д.
Если мы поместим небольшой Thread.Sleep (...) внутрь цикла, он сгенерирует уникальные идентификаторы. Я думаю, что это отвлекающий маневр. Я создал тестовое приложение, которое просто создавало одно руководство за другим и не получало ни одного дубликата.
Моя теория заключается в том, что IL был оптимизирован таким образом, чтобы вызвать такое поведение. Но хватит о моих теориях. Как вы думаете? Я открыт для предложений и способов проверить это.
ОБНОВЛЕНИЕ. Кажется, в моем вопросе много путаницы, поэтому позвольте мне уточнить. Я НЕ думаю, что NewGuid () не работает. Ясно, что это работает. Это отлично! Однако где-то есть ошибка, из-за которой NewGuid () либо: 1) вызываться только один раз в моем цикле 2) вызываться каждый раз в моем цикле, но назначается только один раз 3) еще кое-что, о чем я не думал
Эта ошибка может быть в моем коде (Скорее всего) или где-то в оптимизации.
Итак, повторяя свой вопрос, как мне отладить этот сценарий?
(и спасибо за отличное обсуждение, это действительно помогает мне прояснить проблему в моей голове)
ОБНОВЛЕНИЕ № 2: я бы хотел опубликовать пример, показывающий проблему, но это часть моей проблемы. Я не могу дублировать его за пределами всего набора приложений (клиентских и серверных).
Вот соответствующий фрагмент:
OrderTicket ticket = new OrderTicket(... );
for( int i = 0; i < _numOrders; i++ )
{
ticket.CacheId = Guid.NewGuid();
Submit( ticket ); // note that this simply makes a remoting call
}
О да. Я думал об этом. Но я изначально предполагал, что это, вероятно, будет в оптимизаторе JIT. Для этого нельзя использовать Reflector.
Если вы не думаете, что это ошибка NewGuid, опубликуйте код, который показывает проблему. Или, по крайней мере, опубликуйте код, который было проблема. Также ответьте на вопрос, вызывает ли удаление Thread.Sleep проблему повторного появления проблемы. Я неплохо разбираюсь в экстрасенсорной отладке, но даже лучше с некоторыми деталями.
да. Сон потока заставил его вести себя правильно, а его удаление вернуло ошибку. Моя проблема усугубляется тем, что я совершенно не могу воспроизвести проблему вне всего этого набора приложений.





Это ошибка в вашем коде. Если вам удалось создать несколько руководств, это наиболее вероятное объяснение. Подсказка здесь в вашем вопросе: «когда мы запускали тест после незначительных изменений кода симулятора, все сгенерированные им объекты имели одинаковый Guid»
Ага, я тоже так думал. Но я не мог его найти. Каждая итерация вызывала NewGuid () каждый раз и каждый раз возвращала один и тот же идентификатор. Предложения?
В этом проблема генераторов случайных чисел, никогда нельзя быть уверенным.
Я на это не куплюсь. В руководстве есть некоторая случайность, и да, теоретически дубликаты «возможны», но не КАЖДЫЙ. Очевидно, проблема не в этом. Что-то не так с нашим кодом или оптимизатором. Моя проблема в том, что я не знаю, как это узнать. Предложения?
Как насчет сокращения кода до минимума, который дублирует проблему, и публикации его здесь.
См. Этот статья о том, как создается Guid.
Эта статья пришла из ответа Этот.
Итог, если вы создаете GUID слишком быстро, а часы не сдвинулись вперед, поэтому вы получаете такие же. Однако, когда вы засыпаете, он работает, потому что часы переместились.
Спасибо, но опять же, это мне не помогает. Я знаю, что Guid статистически уникален. Моя проблема НЕ в том, что у меня было 2 из 10 000 гидов, которые были обманутыми. Моя проблема заключалась в том, что 10 000 из 10 000 были обманщиками. Это не статистическая коллизия. Это ошибка. Но где? А как найти?
Извините, мне пришлось проголосовать за то, что вы не полностью прочитали статью, на которую вы ссылаетесь.
Код в Submit и OrderTicket тоже будет полезен ...
Вы повторно используете OrderTicket. Я подозреваю, что либо вы (или само удаленное взаимодействие) выполняете пакетные вызовы - вероятно, в отношении количества соединений / ограничений хоста - и выбираете последнее значение CacheId, когда оно, наконец, отправляет их.
Если вы отлаживаете приложение или Thread.Sleep, вы меняете время, чтобы вызов удаленного взаимодействия завершился до того, как вы назначите новый CacheId.
Вы асинхронизируете удаленный вызов? Я бы подумал, что вызов синхронизации будет заблокирован, но я бы проверил с помощью анализатора пакетов, такого как Wireshark, чтобы быть уверенным. В любом случае, просто переход на создание нового OrderTicket на каждой итерации, вероятно, поможет.
Обновлено: вопрос в нет о том, что NewGuid не работает ... поэтому мой предыдущий ответ был удален.
Я знаю, что это ошибка. Но, как и некоторые другие здесь, вы, кажется, зацикливаетесь на уникальности Guid. Проблема не в этом. Опять же, 2 дублирования из 10 000 будут проблемой уникальности. Я получаю 10 000 таких же гидов.
Если вы знаете, что это ошибка (то есть вы думаете, что это ошибка приложения), то почему заголовок «Дубликат, возвращенный Guid.NewGuid ()» и теория, что это JIT-оптимизатор вызывает проблему?
Что касается фиксации на «уникальности Гида», то это даже близко не к тому, что я утверждал. Отсутствие энтропии или неперехваченный сбой malloc (например) может вызвать всевозможные проблемы, включая повторяющиеся Guids (потенциально - опять же, это надуманная теория, поскольку ваш выбор - это нарушенное мышление).
Пожалуйста, прочтите мое ОБНОВЛЕНИЕ выше. Я не говорю, что NewGuid не работает. Я никогда не собирался даже намекать на это (оглядываясь назад, я просто читаю заголовок своего сообщения, и да, это действительно так звучит ... извините). И у меня нет мышления «избранный сломан». У меня ошибка, которую я не знаю, как ее найти.
Тысячи разработчиков используют Guids в .NET. Если бы Guid.NewGuid () вообще имел тенденцию «застревать» на одном значении, проблема возникла бы давно.
Несомненно, виноваты незначительные изменения кода. Тот факт, что Thread.Sleep (который меньше отвлекающий маневр, чем рыба, гниющая на солнце) «решает» вашу проблему, предполагает, что ваши свойства задаются каким-то странным образом, который не может вступить в силу, пока цикл не перестанет блокироваться (либо завершив или с помощью Thread.Sleep). Я даже готов поспорить, что «незначительное изменение» заключалось в сбросе всех свойств из отдельного потока.
Если вы разместили образец кода, это поможет.
Вы проиграете эту ставку. Это единственный поток, который просто генерирует данные объекта по сети.
Хороший человек. Я собираюсь случайным образом проголосовать за кучу ваших ответов. :) Извините за замечание "рыба гниет на солнце".
Я не знаю подробностей того, как генерируются GUID ... пока. Однако в настоящее время моя орг. разводит GUID со скоростью, которая заставит кроликов посрамить. Так что я могу поручиться за то, что GUID не сломаны .. пока.
Сообщите нам, как это происходит ... звучит интересно.
У меня были бы серьезные проблемы в профессиональном плане, если бы Guid.NewGuid () выдавал ложную информацию каждые несколько миллионов вызовов, не говоря уже о каждом отдельном случае.
Выполняет ли Submit асинхронный вызов или объект тикета переходит в другой поток на любом этапе.
В примере кода вы повторно используете один и тот же объект. Что делать, если Submit отправляет заявку в фоновом потоке после небольшой задержки (и не принимает копию). Когда вы меняете CacheId, вы фактически обновляете все ожидающие отправки. Это также объясняет, почему Thread.Sleep решает проблему. Попробуй это:
for( int i = 0; i < _numOrders; i++ )
{
OrderTicket ticket = new OrderTicket(... );
ticket.CacheId = Guid.NewGuid();
Submit( ticket ); // note that this simply makes a remoting call
}
Если по какой-то причине это невозможно, попробуйте это и посмотрите, остались ли они такими же:
ticket.CacheId = new Guid("00000000-0000-0000-0000-" +
string.Format("{0:000000000000}", i));
@dviljoen: похоже, я все-таки выиграю эту ставку. :)
Мое чутье подсказывает мне, что что-то в этом роде происходит ...
class OrderTicket
{
Guid CacheId {set {_guid = new Guid("00000000-0000-0000-0000-");}
}
Регистрируйте значение CacheId в файле журнала каждый раз, когда он вызывается с трассировкой стека ... Может быть, кто-то еще его устанавливает.
Неа. Он просто обертывает _cacheId, который инициализируется Guid.NewGuid ()
Если вы думаете, что в IL есть ошибка - используйте Reflector, чтобы отследить ее.