如何从GUID生成8个字节的唯一ID?

5Yr*_*DBA 10 .net c#

我尝试在我们的C#应用​​程序中使用long作为唯一ID(不是全局的,仅用于一个会话)用于我们的事件.你知道以下是否会生成一个唯一的长ID?

public long GenerateId()
{
 byte[] buffer = Guid.NewGuid().ToByteArray();
 return BitConverter.ToInt64(buffer, 0);
}
Run Code Online (Sandbox Code Playgroud)

为什么我们不直接使用GUID?我们认为8字节长就足够了.

Mat*_*lia 12

不,它不会.正如在Raymond Chen的博客上多次强调的那样,GUID被设计为整体上是独一无二的,如果你只删除它的一部分(例如,只从其128中删除64个字节),它将失去其(伪)唯一性保证.


是:

客户需要生成一个8字节的唯一值,他们最初的想法是生成一个GUID并丢弃后半部分,保留前八个字节.他们想知道这是不是一个好主意.

不,这不是一个好主意.(...)一旦你看到这一切是如何工作的,很明显你不能丢弃GUID的一部分,因为所有部分(除了固定部分)一起工作以建立唯一性.如果你取走这三个部分中的任何一个,算法就会崩溃.特别是,只保留前8个字节(64位)可以得到时间戳和4个常量位; 换句话说,你拥有的只是一个时间戳,而不是GUID.

由于它只是一个时间戳,因此可能会发生冲突.如果两台计算机同时生成这些"截断的GUID"之一,它们将生成相同的结果.或者,如果系统时钟由于时钟复位而及时反转,您将开始重新生成第一次生成的GUID.


我尝试在我们的C#应用​​程序中使用long作为唯一ID(不是全局的,仅用于一个会话.)用于我们的事件.你知道以下内容会产生一个独特的长ID吗?

你为什么不用柜台?

  • @Aliostad,@Bobby:理论上是正确的,在实践中无关紧要.使用本文中描述的算法,您需要两台具有相同MAC地址的计算机同时生成GUID(理论上低至纳秒),具有相同的时钟序列号.我会说这非常非常*不太可能:).GUID被设计为独特的并且被视为这样,我很确定如果生成重复的GUID,很多软件都会破坏. (4认同)

nat*_*ere 5

您无法将 16 位值提炼为 8 ​​位值,同时仍保持相同程度的唯一性。如果唯一性很重要,不要“推出你自己的”任何东西。除非您真的知道自己在做什么,否则请坚持使用 GUID。

如果相对简单的唯一性实现就足够了,那么生成您自己的 ID 仍然比从 GUID 派生它们更好。以下代码片段摘自我经常使用的“本地唯一标识符”类。它可以轻松定义字符输出的长度和范围。

using System.Security.Cryptography;
using System.Text;

public class LUID
{
    private static readonly RNGCryptoServiceProvider RandomGenerator = new RNGCryptoServiceProvider();
    private static readonly char[] ValidCharacters = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789".ToCharArray();
    public const int DefaultLength = 6;
    private static int counter = 0;

    public static string Generate(int length = DefaultLength)
    {
        var randomData = new byte[length];
        RandomGenerator.GetNonZeroBytes(randomData);

        var result = new StringBuilder(DefaultLength);
        foreach (var value in randomData)
        {
            counter = (counter + value) % (ValidCharacters.Length - 1);
            result.Append(ValidCharacters[counter]);
        }
        return result.ToString();
    }
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,为了明确的人类可读输出,它排除了 1(一)、I(i)、0(零)和 O(o)。

为了确定有效字符和 ID 长度的特定组合的“唯一性”有多有效,数学很简单,但拥有各种“代码证明”(Xunit)仍然很好:

    [Fact]
    public void Does_not_generate_collisions_within_reasonable_number_of_iterations()
    {
        var ids = new HashSet<string>();
        var minimumAcceptibleIterations = 10000;
        for (int i = 0; i < minimumAcceptibleIterations; i++)
        {
            var result = LUID.Generate();
            Assert.True(!ids.Contains(result), $"Collision on run {i} with ID '{result}'");
            ids.Add(result);
        }            
    }
Run Code Online (Sandbox Code Playgroud)