Простое доказательство того, что GUID не уникален

Я хотел бы доказать, что GUID не уникален в простой тестовой программе. Я ожидал, что следующий код будет работать в течение нескольких часов, но он не работает. Как я могу заставить его работать?

BigInteger begin = new BigInteger((long)0);
BigInteger end = new BigInteger("340282366920938463463374607431768211456",10);  //2^128
for(begin; begin<end; begin++)
  Console.WriteLine(System.Guid.NewGuid().ToString());

Я использую С#.

Ответы

Ответ 1

Кай, я предоставил программу, которая будет делать то, что вы хотите, используя потоки. Он лицензируется на следующих условиях: вы должны заплатить мне 0,0001 долл. США за час на процессорное ядро, на котором вы его запускаете. Плата выплачивается в конце каждого календарного месяца. Пожалуйста, свяжитесь со мной для получения информации о моей платежной учетной записи в кратчайшие сроки.

using System;
using System.Collections.Generic;
using System.Linq;

namespace GuidCollisionDetector
{
    class Program
    {
        static void Main(string[] args)
        {
            //var reserveSomeRam = new byte[1024 * 1024 * 100];     // This indeed has no effect.

            Console.WriteLine("{0:u} - Building a bigHeapOGuids.", DateTime.Now);
            // Fill up memory with guids.
            var bigHeapOGuids = new HashSet<Guid>();
            try
            {
                do
                {
                    bigHeapOGuids.Add(Guid.NewGuid());
                } while (true);
            }
            catch (OutOfMemoryException)
            {
                // Release the ram we allocated up front.
                // Actually, these are pointless too.
                //GC.KeepAlive(reserveSomeRam);
                //GC.Collect();
            }
            Console.WriteLine("{0:u} - Built bigHeapOGuids, contains {1} of them.", DateTime.Now, bigHeapOGuids.LongCount());


            // Spool up some threads to keep checking if there a match.
            // Keep running until the heat death of the universe.
            for (long k = 0; k < Int64.MaxValue; k++)
            {
                for (long j = 0; j < Int64.MaxValue; j++)
                {
                    Console.WriteLine("{0:u} - Looking for collisions with {1} thread(s)....", DateTime.Now, Environment.ProcessorCount);
                    System.Threading.Tasks.Parallel.For(0, Int32.MaxValue, (i) =>
                    {
                        if (bigHeapOGuids.Contains(Guid.NewGuid()))
                            throw new ApplicationException("Guids collided! Oh my gosh!");
                    }
                    );
                    Console.WriteLine("{0:u} - That was another {1} attempts without a collision.", DateTime.Now, ((long)Int32.MaxValue) * Environment.ProcessorCount);
                }
            }
            Console.WriteLine("Umm... why hasn't the universe ended yet?");
        }
    }
}

PS: Я хотел попробовать библиотеку расширений Parallel. Это было легко.

И используя OutOfMemoryException, поскольку поток управления просто чувствует себя не так.

ИЗМЕНИТЬ

Ну, похоже, это все еще привлекает голоса. Поэтому я исправил проблему GC.KeepAlive(). И изменил его, чтобы работать с С# 4.

И чтобы уточнить мои условия поддержки: поддержка доступна только в 28/Feb/2010. Пожалуйста, используйте машину времени для запросов поддержки только в этот день.

РЕДАКТИРОВАТЬ 2 Как всегда, GC работает лучше, чем при управлении памятью; любые предыдущие попытки сделать это сами были обречены на провал.

Ответ 2

Это будет работать намного больше, чем часы. Предполагая, что он работает на частоте 1 ГГц (чего не будет - будет намного медленнее, чем), он будет работать для 10790283070806014188970 лет. Это примерно в 83 миллиарда раз дольше, чем возраст Вселенной.

Предполагая закон Moores, было бы намного быстрее не запускать эту программу, подождать несколько сотен лет и запустить ее на компьютере что в миллиарды раз быстрее. На самом деле, любая программа, которая занимает больше времени для работы, чем она требует удвоения скорости процессора (около 18 месяцев), завершится раньше, если вы дождитесь, пока скорость процессора увеличится, и купите новый процессор перед его запуском (если вы не напишете его так, чтобы он могут быть приостановлены и возобновлены на новом оборудовании).

Ответ 3

GUID теоретически не является уникальным. Вот ваше доказательство:

  • GUID - это 128-разрядное число
  • Вы не можете генерировать 2 ^ 128 + 1 или более GUID без повторного использования старых GUID

Однако, если бы вся мощность солнечного света была направлена ​​на выполнение этой задачи, она замерзла задолго до ее завершения.

GUID могут быть сгенерированы с использованием нескольких различных тактик, некоторые из которых принимают специальные меры, гарантирующие, что данный компьютер не будет генерировать один и тот же идентификатор GUID дважды. Поиск коллизий в конкретном алгоритме покажет, что ваш конкретный метод генерации GUID плох, но ничего не докажет о GUID в целом.

Ответ 4

Конечно, GUID могут столкнуться. Поскольку идентификаторы GUID являются 128-битными, просто создайте из них 2^128 + 1 и принцип пигментной дыры должно быть столкновение.

Но когда мы говорим, что GUID уникален, мы действительно имеем в виду, что ключевое пространство настолько велико, что практически невозможно случайно сгенерировать один и тот же идентификатор GUID дважды (предполагая, что мы генерируем GUID случайным образом).

Если вы произвольно генерируете последовательность n GUID, тогда вероятность по крайней мере одного столкновения приблизительно равна p(n) = 1 - exp(-n^2 / 2 * 2^128) (это проблема со дня рождения с указанием количества возможных дней рождения 2^128).

   n     p(n)
2^30 1.69e-21
2^40 1.77e-15
2^50 1.86e-10
2^60 1.95e-03

Чтобы сделать эти числа белыми, 2^60 = 1.15e+18. Итак, если вы генерируете миллиард идентификаторов GUID в секунду, вам потребуется 36 лет для генерации случайных GUID 2^60, и даже тогда вероятность того, что у вас есть столкновение, по-прежнему 1.95e-03. Вы, скорее всего, будете убиты в какой-то момент вашей жизни (4.76e-03), чем вы должны найти столкновение в течение следующих 36 года. Удачи.

Ответ 5

Если вас беспокоит уникальность, вы всегда можете приобрести новые GUID, чтобы вы могли выбросить свои старые. Я положу немного на eBay, если вы хотите.

Ответ 6

Лично я считаю, что "Большой взрыв" был вызван, когда столкнулись два GUID.

Ответ 7

Вы можете показать, что в O (1) время с вариантом алгоритма квантового богосорта.

Guid g1 = Guid.NewGuid();
Guid g2 = Guid.NewGuid();
if(g1 != g2) Universe.Current.Destroy();

Ответ 8

Любые два идентификатора GUID очень уникальны (не равны).

Смотрите эту запись SO > и Wikipedia

Хотя каждый сгенерированный GUID не гарантировано быть уникальным, общее количество уникальных ключей (2 ^ 128 или 3.4 × 10 ^ 38) настолько велика, что вероятность того же числа равна сгенерированный дважды, очень мал. Для Например, рассмотрим наблюдаемые Вселенной, которая содержит около 5 × 10 ^ 22 звезды; каждая звезда могла бы 6.8 × 10 ^ 15 универсально уникальных GUID.

Так что, наверное, вам нужно ждать еще много миллиардов лет, и надеемся, что вы ударите его перед вселенной, поскольку мы знаем, что он подходит к концу.

Ответ 9

[Обновить:] Как отмечают ниже, более новые MS GUID являются V4 и не используют MAC-адрес как часть поколения GUID (я не видел никаких указаний на V5 реализация от MS, хотя, если у кого есть ссылка, подтверждающая, что дайте мне знать). Однако с V4 время все еще остается фактором, и шансы на дублирование GUID остаются настолько малыми, что не имеют никакого значения для любого практического использования. Разумеется, вы вряд ли когда-либо создадите дублирующий GUID только из одного системного теста, такого как OP пытался.

В большинстве этих ответов отсутствует один важный момент в реализации Microsoft GUID. Первая часть GUID основана на отметке времени, а другая часть основана на MAC-адресе сетевой карты (или случайном числе, если NIC не установлен).

Если я правильно понимаю это, это означает, что единственным надежным способом дублирования GUID будет запуск одновременных генераций GUID на нескольких машинах, где MAC-адреса были одинаковыми И, где часы в обеих системах были в одно и то же точное время когда генерация произошла (отметка времени основана на миллисекундах, если я ее правильно понимаю).... даже тогда в числе случайных есть много других бит, поэтому шансы все еще исчезающе малы.

Во всех практических целях GUID универсальны.

Существует довольно хорошее описание MS GUID на "The Old New Thing" блог

Ответ 10

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

internal static class GuidExt
{
    public static bool IsUnique(this Guid guid)
    {
        while (guid != Guid.NewGuid())
        { }
        return false;
    }
}

Чтобы вызвать его, просто вызовите Guid.IsUnique всякий раз, когда вы создаете новый guid...

Guid g = Guid.NewGuid();
if (!g.IsUnique())
{
    throw new GuidIsNotUniqueException();
}

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

Ответ 11

Подсчет до 2 ^ 128 - амбициозный.

Предположим, что мы можем считать 2 ^ 32 идентификатора в секунду на машину - не так уж амбициозно, так как это даже не 4,3 миллиарда в секунду. Давайте посвятим этой машине 2 ^ 32 машины. Кроме того, позволяет каждому из 2 ^ 32 цивилизаций посвятить одни и те же ресурсы задаче.

До сих пор мы могли рассчитывать 2 ^ 96 идентификаторов в секунду, то есть мы будем рассчитывать на 2 ^ 32 секунды (чуть более 136 лет).

Теперь нам нужно всего лишь собрать 4 294 967 296 цивилизаций для каждого из 4 294 967 296 машин, каждый из которых способен подсчитывать 4 294 967 296 идентификаторов в секунду, исключительно для этой задачи в течение следующих 136 лет или около того - я предлагаю начать с этой важной задачи прямо сейчас; -)

Ответ 12

Хорошо, если время работы 83 миллиарда лет не пугает вас, подумайте, что вам также нужно будет хранить сгенерированные GUID где-нибудь, чтобы проверить, есть ли у вас дубликат; для хранения 2 ^ 128 16-байтных номеров потребуется только выделить 4951760157141521099596496896 терабайт оперативной памяти, поэтому, если вы воображаете, что у вас есть компьютер, который может соответствовать всем этим, и что вы как-то найдете место для покупки терабайтных модулей DIMM по 10 граммов каждый, в сочетании они будут весит более 8 масс Земли, поэтому вы можете серьезно сдвинуть его с текущей орбиты, прежде чем вы даже нажмите "Выполнить". Подумайте дважды!

Ответ 13

for(begin; begin<end; begin)
    Console.WriteLine(System.Guid.NewGuid().ToString());

Вы не увеличиваете begin, поэтому условие begin < end всегда истинно.

Ответ 14

Если конфликты GUID вызывают озабоченность, я бы рекомендовал вместо этого использовать ScottGuID.

Ответ 15

Предположительно у вас есть основания полагать, что алгоритм для создания Гидов не создает по-настоящему случайных чисел, а фактически циклически с периодом < 2 ^ 128.

например. RFC4122, используемый для получения идентификаторов GUID, который фиксирует значения некоторых битов.

Доказательство цикличности будет зависеть от возможного размера периода.

Для небольших периодов хэш-таблица хэша (GUID) → GUID с заменой на столкновение если идентификаторы GUID не совпадают (прекратить, если они это сделают), может быть подход. Рассмотрим также замену только случайной доли времени.

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

Обратите внимание, что если метод генерации Гидов основан на времени (см. RFC), то может быть невозможно определить, существуют ли конфликты, потому что либо (а) вы не сможете ждать достаточно долго, чтобы часы или (b) вы не можете запросить достаточное количество гидов в течение такта, чтобы вызвать столкновение.

В качестве альтернативы вы можете показать статистическую зависимость между битами в Guid или корреляцию бит между гидами. Такие отношения могут сделать весьма вероятным, что алгоритм имеет недостатки, не обязательно имея возможность найти фактическое столкновение.

Конечно, если вы просто хотите доказать, что Гиды могут сталкиваться, то ответ на это математическое доказательство, а не программа.

Ответ 16

Но вы должны быть уверены, что у вас есть дубликат, или вам все равно, если может быть дубликат. Чтобы быть уверенным, что у вас есть два человека с одинаковым днем ​​рождения, вам нужно 366 человек (не считая високосного года). Для того, чтобы иметь более 50% шансов иметь двух человек с одним и тем же днем ​​рождения, вам нужно всего 23 человека. Это проблема дня рождения.

Если у вас есть 32 бита, вам нужно только 77,163 значения, чтобы иметь более 50% вероятности дублирования. Попробуйте:

Random baseRandom = new Random(0);

int DuplicateIntegerTest(int interations)
{
    Random r = new Random(baseRandom.Next());
    int[] ints = new int[interations];
    for (int i = 0; i < ints.Length; i++)
    {
        ints[i] = r.Next();
    }
    Array.Sort(ints);
    for (int i = 1; i < ints.Length; i++)
    {
        if (ints[i] == ints[i - 1])
            return 1;
    }
    return 0;
}

void DoTest()
{
    baseRandom = new Random(0);
    int count = 0;
    int duplicates = 0;
    for (int i = 0; i < 1000; i++)
    {
        count++;
        duplicates += DuplicateIntegerTest(77163);
    }
    Console.WriteLine("{0} iterations had {1} with duplicates", count, duplicates);
}

1000 iterations had 737 with duplicates

Теперь 128 бит - это много, поэтому вы все еще говорите о большом количестве предметов, которые все еще дают вам небольшую вероятность столкновения. Вам потребуется следующее количество записей для данных коэффициентов с использованием аппроксимации:

  • 0,8 млрд. млрд. для шанса столкновения на 1/1000
  • 21,7 млрд. млрд. для 50% -ной вероятности столкновения.
  • 39,6 млрд. млрд. на 90% вероятность столкновения.

В год отправляется около 1E14 писем, поэтому на этом уровне будет около 400 000 лет, прежде чем у вас будет 90% -ный шанс иметь два с одинаковым идентификатором GUID, но это намного отличается от того, что вам нужно запустить компьютер в 83 миллиарда раз больше возраста Вселенной или что солнце простудилось, прежде чем найти дубликат.

Ответ 17

Я не понимаю, почему никто не упомянул об обновлении вашей видеокарты... Конечно, если у вас есть high-end NVIDIA Quadro FX 4800 или что-то (192 ядра CUDA), это будет быстрее...

Конечно, если бы вы могли позволить себе несколько NVIDIA Qadro Plex 2200 S4s (каждый из 960 ядер CUDA), этот расчет будет кричать действительно. Возможно, NVIDIA будет готова предоставить вам несколько за "Технологическую демонстрацию" в качестве PR-трюка?

Конечно, они хотели бы быть частью этого исторического расчета...

Ответ 18

Разве вам не хватает основной точки?

Я думал, что GUID были сгенерированы с использованием двух вещей, которые делают вероятность того, что они будут глобально уникальными достаточно высокими. Во-первых, они засеяны MAC-адресом машины, на которой вы находитесь, и два они используют время, в которое они были сгенерированы, плюс случайное число.

Поэтому, если вы не запустите его на самом компьютере и не запустите все, что вы догадываетесь, в течение наименьшего количества времени, которое машина использует для представления времени в GUID, вы никогда не будете генерировать одинаковое число независимо от того, сколько догадок вы используете с помощью системный вызов.

Я предполагаю, что если вы знаете фактический способ создания GUID, фактически сократите время догадки довольно существенно.

Тони

Ответ 19

Вы можете использовать идентификаторы GUID. Таким образом, вы должны получить результат намного быстрее.

О, конечно же, запуск нескольких потоков одновременно - тоже хорошая идея. Таким образом, вы увеличите вероятность того, что состояние гонки будет генерировать один и тот же идентификатор GUID дважды для разных потоков.

Ответ 20

  • Пойдите в лабораторию криогеники в Нью-Йорке.
  • Замораживайте себя (примерно) 1990 года.
  • Получите работу в Planet Express.
  • Купите совершенно новый процессор. Создайте компьютер, запустите программу и поместите ее в безопасное место с помощью псевдо-вечного двигателя, такого как машина конца света.
  • Подождите, пока машина времени не будет изобретена.
  • Переход к будущему с использованием машины времени. Если вы купили 1YHz 128-битный процессор, перейдите к 3,938,453,320 days 20 hours 15 minutes 38 seconds 463 ms 463 μs 374 ns 607 ps после того, как вы запустили программу.
  • ...
  • PROFIT!!!

... Требуется не менее 10,783,127 лет, даже если у вас 1 ГГц процессор, который 1,000,000,000,000,000 (или 1,125,899,906,842,624, если вы предпочитаете использовать бинарный префикс) раз быстрее, чем 1 ГГц.

Поэтому, вместо того, чтобы ждать завершения вычисления, лучше было бы кормить голубя, потерявшего свой дом, потому что другие голубки n забрали их домой.: (

Или вы можете подождать, пока не будет изобретен 128-битный квантовый компьютер. Затем вы можете доказать, что GUID не уникален, используя вашу программу в разумные сроки (возможно).

Ответ 21

GUID - это 124 бита, поскольку 4 бита содержат номер версии.

Ответ 22

Вы пробовали begin = begin + new BigInteger((long)1) вместо begin ++?

Ответ 23

Если количество генерируемого UUID следует закону Мура, впечатление о том, что в обозримом будущем никогда не заканчивается GUID, является ложным.

При использовании 2 ^ 128 UUID, это займет всего 18 месяцев * Log2 (2 ^ 128) ~ = 192 года, прежде чем мы закончим все UUID.

И я верю (без каких-либо статистических доказательств того, что когда-либо) в последние несколько лет после массового принятия UUID, скорость, которую мы генерируем UUID, растет быстрее, чем диктует закон Мура. Другими словами, мы, вероятно, имеем менее 192 лет, пока нам не придется иметь дело с кризисом UUID, что намного раньше, чем конец Вселенной.

Но так как мы определенно не будем их запускать к концу 2012 года, мы оставим его другим видам, чтобы беспокоиться о проблеме.

Ответ 24

Вероятность ошибки в генерации кода GUID намного выше, чем вероятность того, что алгоритм генерирует столкновение. Шансы на ошибку в вашем коде для проверки идентификаторов GUID еще больше. Откажитесь.

Ответ 25

Не нахожусь здесь на костре, но на самом деле это происходит, и да, я понимаю, что вы шутите над этим парнем, но GUID уникален только в принципе, я наткнулся на эту тему, потому что там является ошибкой в ​​эмуляторе WP7, что означает, что каждый раз, когда он загружается, он выдает САМЫЙ GUID при первом вызове! Итак, если теоретически вы не можете иметь конфликт, если есть проблема с созданием GUI, тогда вы можете получить дубликаты

http://forums.create.msdn.com/forums/p/92086/597310.aspx#597310

Ответ 26

Программа, хотя и ее ошибки, показывает, что GUID не уникален. Те, кто пытается доказать обратное, не имеют смысла. Это утверждение просто доказывает слабую реализацию некоторых вариаций GUID.

GUID не обязательно уникален по определению, он по своей сути является уникальным. Вы просто уточнили значение высоко. В зависимости от версии, разработчик (MS или другие), использование VM и т.д. Ваше определение сильно меняется. (см. ссылку в более раннем сообщении)

Вы можете сократить свою 128-битную таблицу, чтобы доказать свою точку зрения. Лучшее решение - использовать хеш-формулу для сокращения вашей таблицы с помощью дубликатов, а затем использовать полное значение после того, как хеш столкнется и на основе этого будет сгенерирован GUID. Если вы работаете в разных местах, вы будете хранить свои пары хэша/полного ключа в центральном месте.

Ps: Если целью является только генерация x числа различных значений, создайте хэш-таблицу этой ширины и просто проверьте значение хэша.

Ответ 27

Поскольку часть генерации Guid основывается на текущем времени машины, моя теория получить дубликат Guid:

  • Выполните чистую установку Windows
  • Создайте стартап script, который сбрасывает время до 2010-01-01 12:00:00 так же, как Windows загружается.
  • Сразу после запуска script он запускает ваше приложение для создания Guid.
  • Отключите эту установку Windows, чтобы исключить любые тонкие различия, которые могут возникать при последующих загрузках.
  • Повторно просмотрите жесткий диск с этим изображением и загрузите компьютер несколько раз.

Ответ 28

Для меня.. время, которое требуется для создания одного ядра для создания UUIDv1, гарантирует его уникальность. Даже в многоядерной ситуации, если генератор UUID позволяет одновременно генерировать один UUID для вашего конкретного ресурса (помните, что несколько ресурсов могут полностью использовать те же UUID, какие маловероятны, поскольку ресурс по своей сути является частью адреса), тогда вы будет иметь более чем достаточно UUID, чтобы продержаться до тех пор, пока метка времени не погаснет. В этот момент я действительно сомневаюсь, что вам все равно.

Ответ 29

Здесь тоже решение:

int main()
{
  QUuid uuid;
  while ( (uuid = QUuid::createUuid()) != QUuid::createUuid() ) { }
  std::cout << "Aha! I've found one! " << qPrintable( uuid.toString() ) << std::endl;
}

Примечание: требуется Qt, но я гарантирую, что если вы позволите ему работать достаточно долго, он может найти его.

(Обратите внимание: на самом деле, теперь, когда я смотрю на него, может быть что-то вроде алгоритма генерации, который предотвращает столкновения двух впоследствии сгенерированных uuids, но я сомневаюсь в этом).

Ответ 30

Единственное решение, чтобы доказать GUID, не уникально, так это иметь World GUID Pool. Каждый раз, когда GUID генерируется где-то, он должен быть зарегистрирован в организации. Или, черт возьми, мы можем включить стандартизацию, чтобы все генераторы GUID должны регистрировать ее автоматически и для этого ей нужно активное подключение к Интернету!