是否可能从GUID生成(高度可能的)唯一整数?
int i = Guid.NewGuid().GetHashCode();
int j = BitConverter.ToInt32(Guid.NewGuid().ToByteArray(), 0);
哪个更好?
是否可能从GUID生成(高度可能的)唯一整数?
int i = Guid.NewGuid().GetHashCode();
int j = BitConverter.ToInt32(Guid.NewGuid().ToByteArray(), 0);
哪个更好?
Eric Lippert写了一篇非常有趣(像往常一样)的文章,讨论了哈希碰撞的概率。
你应该读完整篇文章,但他最后用了这个非常形象的图表作为结论:
针对你的具体问题,我也会选择使用GetHashCode
,因为无论如何都无法避免碰撞。
GetHashCode
函数专门设计用于创建分布均匀且碰撞概率较低的整数范围,因此对于此使用情况,这可能是您能做到的最好的选择。
但是,正如您所知道的那样,将128位信息哈希成32位信息会丢失大量数据,因此如果您拥有足够多的 GUIDs,几乎肯定会发生冲突。
GUID是一个128位整数(只是使用十六进制而不是十进制)。 使用.NET 4时,可以像这样使用http://msdn.microsoft.com/en-us/library/dd268285%28v=VS.100%29.aspx
// Turn a GUID into a string and strip out the '-' characters.
BigInteger huge = BigInteger.Parse(modifiedGuidString, NumberStyles.AllowHexSpecifier)
如果你没有安装 .NET 4,你可以考虑 IntX 或者 Solver Foundation。
以下是最简单的方法:
Guid guid = Guid.NewGuid();
Random random = new Random();
int i = random.Next();
你会注意到这里实际上没有使用guid
,主要是因为没有使用它的意义。Microsoft的GUID算法不再使用计算机的MAC地址,而是使用伪随机生成器(基于时间值)生成GUID,因此如果您想要一个随机整数,最好使用Random
类来生成。
更新: 实际上,使用GUID生成int
可能比仅使用Random
更糟糕(在这种情况下,“更糟糕”指的是这将更有可能生成冲突)。这是因为GUID中并不是所有的128位都是随机的。理想情况下,您希望从哈希函数中排除非变化位,尽管直接生成随机数会更容易,就像我之前提到的那样。 :)如果您想突破2^32的限制,请尝试此方法:
/// <summary>
/// Generate a BigInteger given a Guid. Returns a number from 0 to 2^128
/// 0 to 340,282,366,920,938,463,463,374,607,431,768,211,456
/// </summary>
public BigInteger GuidToBigInteger(Guid guid)
{
BigInteger l_retval = 0;
byte[] ba = guid.ToByteArray();
int i = ba.Count();
foreach (byte b in ba)
{
l_retval += b * BigInteger.Pow(256, --i);
}
return l_retval;
}
在你经历碰撞之前,宇宙将会衰变成一个冷漠黑暗的广袤空间。
我有一个需求,需要多个控制台应用程序获取唯一的整数ID。它用于标识实例并在启动时分配。因为.exe是手动启动的,所以我选择了使用启动时间的tick解决方案。
我的想法是,用户几乎不可能在同一毫秒内启动两个.exe。这种行为是确定性的:如果发生冲突,您就知道问题是两个实例同时启动了。依赖于哈希码、GUID或随机数的方法可能会以不可预测的方式失败。
我将日期设置为0001-01-01,加上当前时间,将ticks除以10000(因为我不设置微秒),以获得一个小到足以放入整数的数字。
var now = DateTime.Now;
var zeroDate = DateTime.MinValue.AddHours(now.Hour).AddMinutes(now.Minute).AddSeconds(now.Second).AddMilliseconds(now.Millisecond);
int uniqueId = (int)(zeroDate.Ticks / 10000);
编辑:有一些注意事项。为了让碰撞变得不太可能,请确保:
/// <summary>
/// The command id to use. This is a thread-safe id, that is unique over the lifetime of the process. It changes
/// at each access.
/// </summary>
internal static int NextCommandId
{
get
{
return _nextCommandId++;
}
}
private static int _nextCommandId = 0;
这将在运行的进程内生成一个唯一的整数值。由于您没有明确定义整数应该有多独特,因此这可能会适合。
这里有一个最简单的解决方案,只需在 Guid
上调用 GetHashCode()
。请注意,guid 是 128 位整数,而 int 是 32 位。因此不能保证其唯一性。但对于大多数实现来说,它可能在统计上足够好。
public override bool Equals(object obj)
{
if (obj is IBase)
return ((IBase)obj).Id == this.Id;
return base.Equals(obj);
}
public override int GetHashCode()
{
if (this.Id == Guid.Empty)
return base.GetHashCode();
return this.Id.GetHashCode();
}
Guid
,那么获得“唯一”(100%)的最佳方法就是在某个地方使用一个整数变量并进行 int++ 操作。你肯定会获得 2^32 个唯一值,而这已经是相当大的空间了。 - nawfal