C# 如何生成绝对唯一的GUID';s

C# 如何生成绝对唯一的GUID';s,c#,C#,是否有一种方法可以每次生成100%的新GUID,而不会在整个应用程序中发生冲突 由于我无法在八小时内回答我的问题,我提出了解决方案: internal static class GuidGenerator { private static readonly HashSet<Guid> _guids = new HashSet<Guid>(); internal static Guid GetOne() { Guid result;

是否有一种方法可以每次生成100%的新GUID,而不会在整个应用程序中发生冲突

由于我无法在八小时内回答我的问题,我提出了解决方案:

internal static class GuidGenerator
{
    private static readonly HashSet<Guid> _guids = new HashSet<Guid>();

    internal static Guid GetOne()
    {
        Guid result;

        lock (_guids)
            while (!_guids.Add(result = Guid.NewGuid())) ;

        return result;
    }
    internal static void Utilize(Guid guid)
    {
        lock (_guids)
            _guids.Remove(guid);
    }
}
内部静态类GuidGenerator
{
私有静态只读哈希集_guids=new HashSet();
内部静态Guid GetOne()
{
指导结果;
锁(_guids)
而(!\u guids.Add(result=Guid.NewGuid());
返回结果;
}
内部静态无效利用(Guid)
{
锁(_guids)
_删除(guid);
}
}
此代码是否解决了应用程序中的问题


编辑:嗯,事情越来越复杂了。线程安全会降低速度。

是生成不会与另一个GUID冲突的GUID的最不可能的方法。除非生成GUID并查看现有GUID以确保它们不存在,否则无法100%确定。

这取决于您想要什么。如果您希望生成的guid之间具有唯一性,那么这是可以实现的。只需维护一个guid列表,每当您需要创建一个新的guid时,都要执行一个循环,直到找到一个不在列表中的guid

如果您想要某种全局唯一性,即全局意味着在整个地球上使用的所有guid之外,那么这是永远无法实现的

var newGuid = Guid.NewGuid();


编辑-我同意@David Heffernan所说的。您可以使用现有的机制来生成最佳唯一标识符,但在这个宇宙中,您可以100%依赖的东西很少。

您可以使用。它将为您生成GUID,我相信您不会与另一个GUID发生冲突。

不,没有任何方法可以生成绝对唯一的GUID。只有3.40282367×1038个可能的GUID,因此星系碰撞时,这些标识符也会发生碰撞。即使对于单个应用程序,它也取决于应用程序有多少guid。除非你的应用程序比谷歌所有的索引器加起来都大,否则你不需要为此而失眠。只需使用
Guid.NewGuid()
而不是100%。但是,如果GUID生成器工作正常,则碰撞概率非常小。这实际上可以算作0

一个随机生成的(种类4)guid大约有120个随机位。从生日问题可以看出,一旦生成大约2^60或10^18个GUI,冲突就很可能发生,这是非常多的

因此,简单地使用
Guid.NewGuid()
就足够了


您提出的解决方案不是一个好主意:

  • 如果您有很多guid,那么它可能会占用大量内存
  • 由于您需要在本地了解所有GUID,因此没有理由首先使用GUID。一个简单的整数计数器也可以完成这项工作
  • 随机GUID冲突比硬件故障损坏数据结构的可能性更小
我觉得你的代码本身是正确的。i、 如果你注册了所有的guid,并且你的硬件工作正常,并且软件没有其他bug,那么你就可以保证不会发生冲突


当然,它也不是线程安全的,这对于静态方法来说是意外的。

如果使用有限数量的字符,那么根据(也称为
Dirichlet
)原则,总是有可能收到冲突。

当然。GUID只是一个128位的值。因此,使用一个128位整数(例如,由两个
ulong
值表示)并将其递增。当达到128位整数类型的最大值时,就生成了所有可能的GUID。例如:

public IEnumerable<Guid> GetAllGuids()
{
    unchecked
    {
        byte[] buffer = new byte[16];
        ulong x = 0UL;
        do
        {
           byte[] high = BitConverter.GetBytes(x);
           Array.Copy(high, 0, buffer, 0, 8);
           ulong y = 0UL;
           do
           {
               y++;
               byte[] low = BitConverter.GetBytes(y);
               Array.Copy(low, 0, buffer, 8, 8);
               yield return new Guid(buffer);
           } while (y != 0UL);
           x++;
        } while (x != 0UL);
    }
}
public IEnumerable GetAllGuids()
{
未经检查
{
字节[]缓冲区=新字节[16];
ulong x=0UL;
做
{
字节[]高=位转换器.GetBytes(x);
复制(高,0,缓冲区,0,8);
ulong y=0UL;
做
{
y++;
字节[]低=位转换器.GetBytes(y);
复制(低,0,缓冲区,8,8);
产生并返回新的Guid(缓冲区);
}而(y!=0UL);
x++;
}而(x!=0UL);
}
}
注:

  • 这肯定没有可能的那么有效
  • 迭代所有可能的
    ulong
    值是一种痛苦-我不喜欢使用
    do…而
  • 如注释中所述,这将产生无效的值
当然,这绝不是随机的


实际上,正如其他人所提到的,来自
Guid.NewGuid
的冲突几率非常小。

如果您在上下文中需要唯一的Guid,只需从00000000-0000-0000-0000-000000000000开始并使用递增。除非达到FFFFFF-FFFF-FFFF-FFFF-FFFF-FFFFFFFF,否则所有通用的GUID都是唯一的。存储当前的GUID对于任何东西都是不切实际的,但对于少量的GUID来说,这将是非常低的冲突机会

在实际场景中,您可能会定期生成数百万甚至数十亿个guid,因此存储128位值以确保唯一guid的开销变得不切实际。(每个GUID 16个字节)

对于仅仅1000000000个GUI,您需要16000000000字节=1565000KB=152588MB=149GB

大表中的查找时间也会使生成新的唯一GUI慢到虚拟爬网(在CPU时间范围内),特别是当新的GUI与现有值发生冲突时,会导致生成新的GUI,然后需要检查这些GUI,等等

生成一个“随机”的128位值,或者甚至使用类似(当前时间*处理器时钟)的东西可能“足够接近”——只有45位足以存储1000年的毫秒计数。128位为9671406556917033397649408倍的值

无论您做什么,即使使用计数器,128位值也会发生冲突。

GUID

电子数据交换