我发现了许多关于生成UID的不同问题,但据我所知,我的要求有点独特(ha)。
总结一下:我需要生成一个非常短的ID,它是“本地”唯一的,但不一定是“全局”或“普遍”唯一。约束不仅仅基于美学或空间问题,而是由于这实际上被用作硬件标签,并且这受到硬件约束的约束。以下是规格:
我知道可以使用少于12个十进制数字将时间戳编码为100 ms甚至10 ms精度,这足以保证此应用程序的“足够唯一”ID。我之所以在SO上提出这个问题的原因,是因为我真的想尝试在那里加入人类可读的年/月或者编写一些关于源机器的信息,或两者兼而有之。
我希望有人可以帮助对这些软性要求做出妥协......或者解释为什么在给定其他要求的情况下,没有人可以做到这一点。
(P.S。我的“原生”语言是C#,但如果有人有任何好主意,任何语言甚至伪代码的代码都可以。)
更新
现在我已经有机会在它上面睡觉了,我认为我实际上要做的是默认使用时间戳编码,并允许单个安装通过定义自己的安装切换到机器序列ID 2位或3位机器ID。这样,想要弄乱ID并打包在人类可读信息中的客户可以找出他们自己确保唯一性的方法,我们对滥用不负责任。也许我们通过提供服务器实用程序来帮助处理机器ID,如果它们碰巧正在进行所有在线安装。
答案 0 :(得分:4)
“我在这里问这个问题的原因 所以,是因为我真的很想 要么尝试合并 人类可读的年/月在那里或 编码一些关于的信息 源机器,或两者兼而有之。“
首先让我说我之前已经处理过这个问题,并且尝试将有用的信息存储到序列号中是一个长期不好的想法。设备序列号应该没有意义。就像数据库记录的主键应该没有意义一样。
第二个你开始尝试将真实数据放入序列号中,你只是将BUSINESS LOGIC抛入其中,你将被迫像任何其他代码一样维护它。未来你会恨你过去。相信我。 ; O)
如果您尝试存储日期/时间值,那么您将浪费具有无效时间/日期的数字空间。例如,您在月份字段中永远不会有大于12的内容。
一个直的纪元/单位时间计数器会更好,但对于每分钟只生成几个id的机器,你仍然会浪费很多空间。
12位不是很大的空间。查看Wikipedia上的VIN页面。只有少数制造商的空间,只有几千辆汽车。他们现在正在重复使用VIN,因为它们通过在其中包含意义而耗尽了空间。
http://en.wikipedia.org/wiki/VIN
这并不是说序列号中的所有含义都不好,只是严格限制它以确保数字不会发生碰撞。
像这样......
你需要避免碰撞 ALL 。如果你添加一个位置数字,那么当你到达11个地点时就会被搞砸。
对不起,如果这听起来像个咆哮。我处理了很多制造电子产品和各种机加工零件。除非有大量可用空间或次要标签(哇 - 提供之前提到的必要id空间),否则它永远不会长期结束。
答案 1 :(得分:3)
安装软件时,还要安装包含唯一数字ID的machi id文件/注册表项。由于您只有几台机器,因此不应超过3或4位数。使用这些作为MS数字。从1开始按顺序生成剩余数字。
答案 2 :(得分:3)
yyMMddhhmmID
怎么样?
yy = two-digit year
MM = two-digit month
dd = two-digit day
hh = two-digit hour (24-hour time)
mm = two-digit minute
ID = machine-specific ID
示例:来自0912113201
的计算机的ID = 01
。
或者(如果你不喜欢两位数年份(Y2K lol)),yyyyMMIDxxxx
怎么样?
yyyy = four-digit year
MM = two-digit month
ID = machine-specific ID
xxxx = sequentially-incremented integer
示例:来自200912010001
的计算机的ID = 01
。
正如您所说,每台机器每五分钟只生成一个最大标识符,这为您提供了每月8,928(24 * 31 * 60/5 = 8928)个标识符的空间,适合xxxx
。如果您需要yyy
序列中的额外数字或机器ID,您可以在这里将年份缩减到三位数年xxxx
(例如009)。
这两个都符合您的要求时间戳/机器ID。
我们都喜欢具体的代码:
class Machine {
public int ID { get; private set; }
public Machine(int id) {
ID = id;
}
}
class IdentifierGenerator {
readonly Machine machine;
int seed;
const int digits = 4;
readonly int modulus;
readonly string seedFormat;
public IdentifierGenerator(Machine machine) {
this.machine = machine;
this.modulus = (int)Math.Pow(10, digits);
this.seedFormat = new string('0', digits);
}
public string Generate() {
string identifier = DateTime.Now.ToString("yyyyMM")
+ machine.ID.ToString("00")
+ seed.ToString(seedFormat);
seed = (seed + 1) % modulus;
return identifier;
}
}
Machine m = new Machine(1);
IdentifierGenerator gen = new IdentifierGenerator(m);
Console.WriteLine(gen.Generate());
Console.WriteLine(gen.Generate());
输出:
200912010000
200912010001
答案 3 :(得分:1)
我正在收集你正在为Windows开发(重新:关于“MSI / EXE”的评论以回应Jason的回答)。因此,您可以通过WMI或类似方式获取一些独特的硬件属性(例如处理器或HDD序列号,或NIC的MAC地址),以基于唯一的计算机ID。另一种方法可能是使用您自己开发的硬件的唯一序列号(如果有的话)。
这很可能比您需要的时间长,因此您可能会截断或散列它以将其减少到(例如)16位左右,并将其用作您的计算机ID。显然,这可能会导致冲突,但是少量的机器(~100)意味着这是不太可能的,并且使用加密哈希的截断输出(比如MD5)会使这种情况更加糟糕。
然后,由于您拥有(最可能是唯一的)计算机ID,因此您可以使用其他答案列出的方法生成基本上唯一的ID。
答案 4 :(得分:0)
24小时内有864000个100ms的刻度,因此将其添加到日期可能会起作用09.12.24.86400.0,但是您必须丢失世纪以适应12位数,并且您没有机器ID的空间
答案 5 :(得分:0)
理念第一:
YYMMDDmmnnnn
,其中
YY is two digit year
MM is two digit month
DD is two digit day
mm is a two digit code unique to that machine (00 - 99)
nnnn is a sequential four digit code for that machine on that day.
~~
第二个想法:
mmmmnnnnnnnn
哪里
mmmm is four digit code unique to the machine
nnnnnnnn is a sequential number.
答案 6 :(得分:0)
我的建议是在一个id中组合多种方法。例如:以两年数字,两个月数字开头,然后生成一个随机数,时间作为下几个数字的种子,然后是最后一对数的唯一机器ID。或类似的东西。
答案 7 :(得分:0)
每台机器都获得DDNNN的起始ID,其中DD是唯一的机器标识符,NNN是该机器当天生成的当前标识符。每台机器都会跟踪它在特定日期生成的ID,并在需要新的ID时通过将最后一个增加1来分配下一个。它会在每天开始时将其计数器重置为0。 YYYYDOY日期前置于每台机器生成的数字(4位数年份,3位数日期)。由于机器标识符是唯一的,因此该数字是唯一的。
如果您需要更多空间用于更多机器,您可以从年份中删除千禧年并为机器ID添加一个数字:YYYDOYDDDNNN。
答案 8 :(得分:0)
“单台机器不会每隔5分钟左右生成ID”
假设这是真的,那么只需使用时间戳。 (32位Unix时间有10位小数,但会在2038年用完)
但我认为假设不会发生碰撞相当乐观。
“从特定计算机生成的ID应该是顺序显示的。”
然后您唯一的选择是使用序列号。
哪个似乎与您在后来的约束中所说的不匹配?
连接节点标识的填充版本以获取整个集群中的唯一值。
答案 9 :(得分:-1)
将机器的MAC地址用作MACHINE ID。您可以使用它来编码时间戳,即通过XOR编码,或者您可以将其添加/添加到生成的序列化代码中。