Побитовая манипуляция в C # для генерации уникального номера - PullRequest
0 голосов
/ 28 марта 2012

Я пытаюсь сгенерировать уникальные значения в c # с помощью тиков DateTime и увеличивающегося числа. Псевдокод:

  1. Возьмите последние 43 значащих бита из DateTime.Now тиков (давайте назовем его A)
  2. Возьмите последние 21 бит из возрастающей последовательности (назовем это 'B')
  3. Сдвиг влево 'A' 21 раз (назовем его 'C')
  4. Делать двоичные ИЛИ в A и C

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

Вот фрагмент кода, который делает это:

    private static long _sequence = 1;
    public static long GetUniqueNumber()
        {
            const int timeShift = 21;            
            var dateTime = DateTime.Now.Ticks;
            const long dateTimeMask = ~(0L) >> timeShift; 
            const long sequenceMask = ((~(0L) >> (64 - timeShift))); 
            var seq = Interlocked.Increment(ref _sequence);
            var dateTimeNo = (dateTimeMask & dateTime) << timeShift;
            var seqNum = (seq & sequenceMask);    
            var num = dateTimeNo | seqNum;
            return num;
        }

У меня есть два вопроса: 1. Достаточно ли хороша эта логика для генерации уникальных чисел? 2. Я считаю, что некоторые сгенерированные числа - это «-ve», которые я не понял.

Любая помощь / предложения / улучшения приветствуются.

Ответы [ 2 ]

6 голосов
/ 28 марта 2012

Достаточно ли хороша эта логика для генерации уникальных чисел

Уникальный в каком объеме? На нескольких компьютерах / процессов / AppDomain s?, Конечно, нет. В пределах одного AppDomain? На самом деле, нет. Генерация 2 миллионов чисел не имеет значения - это просто проверка того, что ваша часть последовательности работает. (2 21 составляет чуть более 2 миллионов.)

Если вы можете позвонить GetUniqueNumber 2 21 + 1 раз в пределах гранулярности DateTime.Now (что, вероятно, будет ~ 10-15 мс), то вы получите повторение. Вы измерили, как быстро ваш компьютер может назвать это?

Тогда есть тот факт, что эти 43 бита будут повторяться за 2 43 тактов ... или, по крайней мере, было бы, если бы у вас были достаточно мелкозернистые часы. (И рано или поздно гранулярность сработает против вас.)

Я обнаружил, что некоторые сгенерированные числа являются "-ve", которые я не понял.

Всякий раз, когда для dateTimeNo установлен верхний бит (из 43), вы получите long с установленным верхним битом, что означает, что он будет отрицательным.

РЕДАКТИРОВАТЬ: Также обратите внимание, что ваш сдвиг нарушен. Это:

const long dateTimeMask = ~(0L) >> timeShift;

выполняется сдвиг с расширенным знаком - так что вы просто получаете ~ 0L.

Вкратце: используйте Guid.NewGuid. Вот для чего это.

0 голосов
/ 28 марта 2012

Отрицательные числа обусловлены реализацией long. Так как это число со знаком, если MSB, который является битом 64, становится «1» после побитовой манипуляции, число станет отрицательным. Ничего страшного в этом нет.

...