生成随机唯一代码

本文关键字:代码 唯一 随机 | 更新日期: 2023-09-27 17:55:02

我需要生成一个九位数的数字代码(最好是随机的),这是唯一的给定日期(相同的数字不能在同一天再次生成)。我正在考虑使用HHMMSSmmm(小时,分钟,秒和毫秒)来生成唯一的代码,但不是真正随机的。这个代码生成方法可以被多个方法同时访问,所以我必须对该方法加一个锁。但是,这是否可以确保数字是唯一的,因为数字生成可能花费不到一毫秒的时间,并且两个线程得到相同的数字?

是否有更好的方法来生成一个随机唯一的数字代码,这是唯一的给定日期?取值范围为6 ~ 9位

Edit:生成随机数的数量取决于事务的数量。最初这个数字可能比较低,但经过一段时间后它可能会变得非常高(每秒处理多个事务)。因此,我不希望将数字与已使用列表进行比较,因为这可能会产生性能问题。

需要随机性,因为该号码将由用户在手机上输入。这个号码是连接在线交易和电话交易的唯一方式,所以我不希望用户错误地输入不同的号码。

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

生成随机唯一代码

如果你从一个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;
            }
        }
    }
}
我认为这符合你的要求……我错了吗?

如果我是,就告诉我,我会尽量多帮你。

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

有什么理由不保留一个计数器,每次自动增加,然后在日期过期时重置它?

使用guide . newguid()获取如下内容:

0 f8fad5b d9cb - 469 f - a165 - 70867728950 e

然后,去掉'-',并将字母转换为对应的ASCII字符。(= 97)

然后转换为数字。

我会

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

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

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

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

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

我看到你增加了一个要求,数字是随机的。如果您希望数字是随机且唯一的,我认为除了保留所有先前分配的数字的列表之外,没有其他选择。你可以把它们保存在某种哈希表中这样你就不用每次都搜索整个列表了。如果你分配了很多这样的元素,那么哈希表的大小可能会开始成为一个问题,即使你不需要按顺序搜索它。

根据你想要完成的任务,你可以提出一种方案,以非顺序但严格的顺序分配数字,因此在某些目的下,它们看起来是随机的。例如,你可以增加一个相对于最大值来说非常大的数并且相对于最大值素数,然后每增加一次,就减去最大值。就像把它缩小,假设你分配的是2位数而不是9位数。增量37。然后将37,74,111个wrap分配给11,48,85,122个wrap分配给22,等等。

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

所以如果代码只要求每天唯一,那么只需使用日期作为代码…

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

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

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

  • 随机数
  • 独特号码。

你需要一些随机的唯一数字。如果从一天开始的毫秒数没有足够的随机外观,可以尝试将其与另一个唯一数字组合。

例如:

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

为例,当你对它们求和时,你可以生成:999999999-86400000 = 913599999个每天唯一的号码

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

这里有一些变化,例如不在00:00重置计数器。

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

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

的好处

  • 确保号码不重复使用,而不与现有列表核对
  • 数字将是随机的,没有任何顺序
  • 应用简单的完整性规则初始化Shuffle Bag,例如不允许通用/重复序列(1111111或123456789)
  • 简单的初始化洗牌袋-使用随机序列号。即从六位数开始,不断添加一个小随机数来初始化包。
  • 便于根据历史使用情况修改袋的大小。
  • c#中非常简单的线程安全实现。

原始源代码在这里-修改后的版本可能会满足您的目的。

  • 永无止境的洗牌序列-当随机太随机

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

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

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

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

如果号码生成方法调用在时间上的分布是均匀的,则任何模式都是几乎相等的。

无论如何,考虑到随机数长度限制,在冲突发生之前总是有一个方法调用数量的限制。例如,if方法每秒被调用> 1000次。

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

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

public double GetRandomNumber() {object operation = new object(); lock(operation) { return new Random().NextDouble(); } }就可以。

这并不取决于日期/时间,因此它比你的要求更随机。现在这个数字小于1,我将留给你作为练习……

另外,如果您想跟踪给定日期生成的所有数字-保留它们的列表,并在生成副本时重新生成。但我不会为你写,因为你是你这种情况下的程序员……

取决于需要多少随机性,您可能正在寻找具有适当参数的线性同余生成器。例如,按照维基百科关于周期长度的条目给出的指导方针,一组参数可能对您有用:M=1000000000, a=21, c=3,然后使用任意初始种子X0 in [0..]999999999),计算X <子> n + 1 = (a * X <子> n + c) % M。这将生成周期为M的Xn序列,即该序列生成[0..]中的所有数字。