生成随机唯一代码

时间:2011-05-05 06:18:14

标签: c# .net algorithm random

我需要生成一个九位数的数字代码(最好是随机的),它对于给定的一天是唯一的(同一天不能再生成相同的数字)。我正在考虑使用HHMMSSmmm(小时,分钟,秒和毫秒)来生成唯一代码但不是真正随机的。这个代码生成方法可以同时通过多种方法访问,因此我将不得不锁定该方法。但这是否会确保数字是唯一的,因为数字生成可能需要不到一毫秒而两个线程可以获得相同的数字?

是否有更好的方法来生成随机唯一数字代码,该代码在给定日期内是唯一的?位数可以是6到9位。

编辑:要生成的随机数的数量取决于交易次数。最初数量可能较低,但在一段时间内它可能变得非常高(每秒多次交易)。因此,我不想将数字与使用的列表进行比较,因为这可能会出现性能问题。

需要随机性,因为用户将在手机上输入此号码。此号码是将在线交易与电话交易相关联的唯一方式,因此我不希望用户错误地输入其他号码。

随机数生成需要在ASP.NET MVC应用程序中进行。

13 个答案:

答案 0 :(得分:3)

如果你从一个6位数的随机数开始,那么继续添加随机数,但数量足够小,你可能能够做到这一点。如果您愿意,可以使用文件系统作为锁定存储...但我认为您应该使用DB进行生产!

以下是我所说的示例:

此示例是一个控制台应用程序,它使用文件来控制并发,并存储最后使用的数字和生成日期。

如果多次运行,您将看到会发生什么。两者都有自己独特的数字。

不会按照您的要求存储所有生成的数字

此样本每天可生成约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 :(得分:1)

编辑:当我意识到每天要求拥有多个唯一代码时,这个答案没有意义,但是他们可以在第二天重复。如果您每天都在寻找一个唯一的代码(无论出于何种原因),那么这个答案很有用:)

因此,如果代码每天只需要是唯一的,那么只需使用日期作为代码......

也许YYYYmmdd,这将给你(今天的日期)20110505,明天将是20110506。

答案 2 :(得分:1)

它只需要在流程中是唯一的吗?

任何理由不保留每次原子增量的计数器,然后在日期结束时重置它?

答案 3 :(得分:1)

如果所有调用都在同一个JVM中,我认为您需要的是创建一个静态来保存最后分配的数字,写一个函数来增加数字并返回新值,然后同步它。像:

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

如果有多个JVM,最简单的方法是将数字存储在数据库中并使用数据库锁定来保持数字唯一。

<强>更新

我看到你添加了一个要求数字是随机的要求。如果您希望数字是随机且唯一的,我看不到保留所有先前分配的数字列表的任何替代方法。您可以将它们保存在某种哈希表中,这样您就不必每次都搜索整个列表。如果你分配了很多这些哈希表的大小可能会开始成为一个问题,即使你不必按顺序搜索它。

根据您要完成的任务,您可以提出一种方案,该方案按顺序分配数字,但是按照严格的顺序,因此出于某些目的,它们会显得随机。例如,您可以增加一个非常大的数字,相对于最大值和相对素数的最大值,然后每次下一个增量将超过时,减去最大值。就像缩小它一样,假设您分配的是2位数而不是9位数。增加37.然后你将37,71,111包裹分配给11,48,85,122包裹到22等等。

答案 4 :(得分:1)

我会

  1. 在每天开始时生成一组唯一的随机数,或者更确切地说,在每天的适当时间之前生成

  2. 每次需要时,从堆栈中顺序取一个数字

答案 5 :(得分:1)

不能确保随机数不会重复。 (因为,他们是随机的)

如果不与已生成的数字进行比较,您可以:

  • 随机数
  • 唯一号码。

您需要具有随机外观的唯一编号。如果从一天开始的毫秒数没有足够的随机外观,请尝试将其与另一个唯一编号组合。

例如:

  • 结合毫秒数和
  • 原子计数器(每次生成数字时递增1)

例如,当您对它们求和时,您可以生成: 999999999-86400000 =每天913599999个唯一数字。

虽然它们不是随机的,但它们将是唯一的 - 并且只能在00:00预测。

以下是此类变体,例如在00:00没有重置计数器。

答案 6 :(得分:1)

Shuffle Bag 的修改版本怎么样?以下是它的工作原理 -

  1. 在您的一天开始之前,您将一个满足您标准的N个不同数字放入随机包中
  2. 在一天中,你从洗牌袋请求一个号码。
  3. 随机包给你一个随机数字并丢弃它 - 即不再返回相同的数字。
  4. 在一天结束时它将清理袋子,为第二天做好准备。
  5. 优势

    • 确保不重复使用号码,而不检查现有列表
    • 数字是随机的,没有任何序列
    • 应用简单的健全规则来初始化Shuffle Bag,例如:不允许共同/重复序列(1111111或123456789)
    • 简单地初始化随机包 - 使用随机序列号。即从六位数开始,继续添加一个小的随机数来初始化包。
    • 根据历史使用情况轻松修改行李尺寸。
    • c#中非常简单的线程安全实现。

    原始来源是here - 修改后的版本可能符合您的目的。

答案 7 :(得分:0)

将一个线程id附加到代码的末尾以处理并发。

答案 8 :(得分:0)

使用Guid.NewGuid()来获得类似的内容:

0f8fad5b-d9cb-469f-a165-70867728950e

然后,摆脱'-'s,并将字母转换为ASCII对应字母。 (其中a = 97)

然后转换为数字。

答案 9 :(得分:0)

合适的代码生成器取决于周期中应生成多少个数字。 考虑以下模式:

HHMMSS + NNN-为您提供一秒钟内999个随机数的空间。

HH + NNNNNNN - 为您提供一小时内9999999个随机数的空间。等

如果数字生成方法调用时间分布均匀,则任何模式几乎相等。

无论如何,考虑到随机数长度限制,在碰撞之前总是存在对方法调用数量的限制。例如。如果调用方法&gt;每秒1000次。

答案 10 :(得分:0)

我继续你的想法使用当前时间,我只是添加了多线程同步,并存储使用过的randoms来比较所有下一个random与它们,以提供唯一性。

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;
}

答案 11 :(得分:0)

public double GetRandomNumber() {object operation = new object(); lock(operation) { return new Random().NextDouble(); } }会这样做。

这不取决于日期/时间,因此它比您的要求更加随机。 现在这个数字不到1的事实我会留给你作为练习...

此外,如果您想跟踪给定日期生成的所有数字 - 保留它们的列表,并在生成重复项时重新生成。但是我不会为你写信,因为你是你所处理的程序员......

答案 12 :(得分:0)

根据需要多少随机性,具有适当参数的linear congruential generator可能是您正在寻找的。例如,遵循维基百科条目中关于周期长度的指南,可能适用于您的一组参数是:M = 1000000000,a = 21,c = 3,然后使用任何初始种子X 0 in [0..999999999],并计算X n + 1 =(a * X n + c)%M。这将生成一个带有周期M的X n 序列,即序列在开始重复之前仅在[0..999999999]中生成一次所有数字。