Генерация случайного уникального кода - PullRequest
8 голосов
/ 05 мая 2011

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

Есть ли лучший способ генерировать случайный уникальный числовой код, которыйуникален для данного дня?Количество цифр может быть от 6 до 9 цифр.

Редактировать: Количество генерируемых случайных чисел зависит от количества транзакций.Первоначально число может быть ниже, но в течение определенного периода времени оно может стать очень высоким (несколько транзакций в секунду).Следовательно, я не хотел бы сравнивать число с используемым списком, поскольку это может иметь проблемы с производительностью.

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

Генерация случайного числа должна выполняться в ASP.NET MVC.применение.

Ответы [ 13 ]

3 голосов
/ 13 мая 2011

Если вы начинаете со случайного числа из 6 цифр, а затем продолжаете добавлять случайные, но достаточно маленькие числа, вы можете сделать это. Вы можете использовать файловую систему в качестве хранилища блокировки, если хотите ... но я думаю, что вы должны использовать БД для производства!

Вот пример того, о чем я говорю:

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

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

Это НЕ будет хранить все сгенерированные числа , как вам нужно!

Этот образец может генерировать около 999000 случайных чисел в день в диапазоне от 6 до 9 цифр включительно. Это примерно 11 номеров в секунду.

using System;
using System.IO;
namespace _5893408
{
    class Program
    {
        static void Main(string[] args)
        {
            Random rand = new Random();
            var futureTime = DateTime.Now.AddSeconds(60);
            while (DateTime.Now < futureTime)
                Console.WriteLine(GetNextNumber(rand));
        }

        public static int GetNextNumber(Random rand)
        {
            var now = DateTime.Now;
            string filePath = @"C:\num.txt";
            FileStream fileStream = null;
            while (fileStream == null)
            {
                try { fileStream = File.Open(filePath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None); }
                catch { }
            }
            using (fileStream)
            {
                DateTime date;
                int prevNum;
                if (fileStream.Length == 0)
                {
                    date = now;
                    prevNum = rand.Next(100000, 999999);
                }
                else
                {
                    var reader = new StreamReader(fileStream);
                    {
                        date = DateTime.Parse(reader.ReadLine());
                        prevNum = int.Parse(reader.ReadLine());
                    }
                    if (date.DayOfYear != now.DayOfYear)
                        prevNum = rand.Next(100000, 999999);
                }
                int nextNum = prevNum + rand.Next(10, 1000);
                fileStream.Seek(0, SeekOrigin.Begin);
                using (var writer = new StreamWriter(fileStream))
                {
                    writer.WriteLine(now);
                    writer.WriteLine(nextNum);
                }
                return nextNum;
            }
        }
    }
}

Я думаю, что это соответствует вашим требованиям ... я не прав?

Если я, просто скажи, и я постараюсь помочь больше.

1 голос
/ 14 мая 2011

Как насчет модифицированной версии Shuffle Bag .Вот как это будет работать - за

  1. до начала дня вы кладете N различных чисел, удовлетворяющих вашему критерию, в случайную сумку
  2. в течение дня, вы запрашиваете номер услучайная сумка.
  3. Сумка Shuffle дает вам случайное число из сумки и сбрасывает ее - то есть больше не вернет тот же номер.
  4. в конце дня она очистит сумку и будет готова к следующему дню..

Преимущества

  • Гарантирует, что номер не будет повторно использоваться без проверки с существующим списком
  • Числа будут случайными, без какой-либо последовательности
  • Применяйте простые правила здравомыслия для инициализации Shuffle Bag, например, не допускаются общие / повторяющиеся последовательности (1111111 или 123456789)
  • Простота инициализации Shuffle Bag - используйте случайные последовательные числа.то есть начинайте с шестизначного числа, продолжайте добавлять небольшое случайное число для инициализации мешка.
  • Легко изменить размер мешка, основываясь на историческом использовании.
  • Очень простая поточно-ориентированная реализация в c #.

Исходный источник здесь - измененная версия может служить вашим целям.

1 голос
/ 05 мая 2011

Если все вызовы находятся в одной и той же JVM, я думаю, что все, что вам нужно, это создать статический объект для хранения последнего назначенного номера, написать одну функцию для увеличения номера и возврата нового значения, а затем выполнить синхронизацию поЭто.Например:

public class NumMaker
{
  static long num=0;
  public static synchronized next()
  {
    return ++num;
  }
}

Если существует несколько JVM, проще всего сохранить номер в базе данных и использовать блокировку базы данных для сохранения уникальности номеров.

Обновление

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

В зависимости от того, что вы пытаетесь выполнить,Вы могли бы придумать схему, которая присваивает числа не последовательно, а в жесткой последовательности, поэтому для некоторых целей они будут казаться случайными.Например, вы можете увеличить число на очень большое по отношению к максимуму и относительно простое с максимумом, а затем каждый раз, когда будет проходить следующий шаг, вычитать максимум.Например, чтобы уменьшить его, предположим, что вы назначали 2-значные числа вместо 9-значных.Увеличьте на 37. Затем вы назначите 37, 74, 111 оберток на 11, 48, 85, 122 оберток на 22 и т. Д.

1 голос
/ 12 мая 2011

Вы НЕ МОЖЕТЕ убедиться, что случайные числа не повторятся. (потому что они случайные)

Без сравнения с уже сгенерированными числами вы можете иметь:

  • случайное число ИЛИ
  • уникальный номер.

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

Например:

  • объединяет количество миллисекунд и
  • атомный счетчик (который увеличивается на единицу каждый раз, когда вы генерируете число)

например, когда вы их суммируете, вы можете сгенерировать: 999999999-86400000 = 913599999 уникальных номеров за один день.

Хотя они не будут случайными, они будут уникальными - и предсказуемыми только в 00:00.

Вот варианты для этого, например, не сбрасывать счетчик в 00: 00.

1 голос
/ 05 мая 2011

Я бы

  1. Генерация набора уникальных случайных чисел в начале каждого дня или, скорее, перед каждым днем ​​в подходящее время

  2. Последовательное извлечение числа из стека каждый раз, когда оно необходимо

1 голос
/ 05 мая 2011

Должен ли он быть уникальным только внутри процесса?

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

1 голос
/ 05 мая 2011

РЕДАКТИРОВАТЬ: Этот ответ не имеет смысла, когда я понял требование иметь несколько уникальных кодов в день, но они могут повторяться на следующий день.Если вы искали один уникальный код в день (по какой-либо причине), тогда этот ответ полезен:)

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

возможно ГГГГммдд, который даст вам (на сегодняшний день) 20110505, а завтра будет 20110506.

0 голосов
/ 12 мая 2011

В зависимости от того, сколько требуется случайности, линейный конгруэнтный генератор с соответствующими параметрами может быть тем, что вы ищете. Например, следуя указаниям, приведенным в записи в Википедии о продолжительности периода, набор параметров, которые могут работать для вас, будет: M = 1000000000, a = 21, c = 3, затем используйте любое начальное начальное число X 0 * 1004. * в [0..999999999] и вычислите X n + 1 = (a * X n + c)% M. В результате генерируется последовательность X n с периодом M, то есть последовательность генерирует все числа в [0..999999999] ровно один раз, прежде чем начать повторение.

0 голосов
/ 12 мая 2011

public double GetRandomNumber() {object operation = new object(); lock(operation) { return new Random().NextDouble(); } } будет делать.

Это не зависит от дня / времени, поэтому оно даже более случайное, чем ваше требование. Теперь тот факт, что число меньше 1, я оставлю вам в качестве упражнения ...

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

0 голосов
/ 12 мая 2011

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

private static DateTime DateInArray = DateTime.Today;
private static ICollection<string> UsedTodayRandoms = new List<string>();

[MethodImpl(MethodImplOptions.Synchronized)]
public static string RandomUniqueToday()
{
    if (! DateTime.Today.Equals(DateInArray) ) {
        UsedTodayRandoms.Clear();
        DateInArray = DateTime.Today;
    }

    string result = null;
    DateTime timeToGenerateUnique = DateTime.Now;
    do
    {
        result = timeToGenerateUnique.ToString("HHmmssfff");
        timeToGenerateUnique = timeToGenerateUnique.AddMilliseconds(-1);
    } while (UsedTodayRandoms.Contains(result));
    UsedTodayRandoms.Add(result);

    return result;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...