使用 DateTime.Now.Ticks 生成唯一的数字 ID

问题描述 投票:0回答:8

我需要生成一个唯一的数字 ID 附加到传入请求。该 ID 仅临时用于跟踪请求,一旦请求完成处理,该 ID 将被丢弃。该 ID 仅在此应用程序的上下文中使用,但需要以高性能多线程方式分配。

我正在考虑使用 DateTime.Now.Ticks 作为此 ID,但想知道如果同时处理并发请求,DateTime.Now.Ticks 是否仍然可以生成冲突 ID?

如果有人可以建议一种在多线程环境中生成这些 ID 的更好方法(最好不是像 Tick 这样的 Int64 的方法),请告诉我。只要我不必在递增之前锁定数字,像递增数字这样简单的东西就足够了。

c# .net multithreading algorithm concurrency
8个回答
14
投票

您只需要使用一个静态变量,每次您需要另一个唯一值时该变量就会递增。您可以使用 Interlocked.Increment 方法使该线程安全并且仍然非常快...

// Declaration
private static int safeInstanceCount = 0;

// Usage
{
      ...
      Interlocked.Increment(ref safeInstanceCount);
      ...
}

7
投票

DateTime.Now
对于这个目的来说绝对是糟糕的。最好的情况下,您的分辨率为 1 毫秒;最坏的情况下,NT 为 17 毫秒,CE/Compact Framework 为 1 秒(!)。

考虑使用

Interlocked.Increment
方法来实现快速、线程安全的计数器。


4
投票

从每线程 ID 开始(如果多个线程发起请求),与每线程计数器连接(如果每个线程预计发起多个请求)。


2
投票

只需获取一个强随机数或使用 GUID

如果高性能是必须具备的特性,请以单调的顺序分配连续的数字。通过为每个处理消息的线程“保留”一系列(例如 20-100)ID 来防止锁争用。这样,您只需在 20-100 次迭代中锁定序列生成器一次。


1
投票

如果您知道将拥有多少个线程(或至少有一个上限),则可以在线程之间划分 ID 空间,将 ID 计算为(线程本地)计数器的值和线程的 ID - 例如,

counter_value++ << 8 | thread_id
。因此,线程之间不需要协调或锁定,生成 ID 仅需要增量、位移和或。

如果为此使用系统线程 ID,您的 ID 会稍微长一些,但您不需要手动为线程分配 ID。


0
投票

你可以使用这样的东西。这是线程安全的、快速的,并且即使应用程序重新启动,也永远不会生成相同的数字,因为它与日期时间连接。

private static int safeInstanceCount = 0;
public static string GenerateUniqueId()
{
    Interlocked.Increment(ref safeInstanceCount);
    var uniqueNumber = long.Parse(DateTime.Now.ToString("yyMMddHHmmss"));
    return $"AnyPreffix-{uniqueNumber}{safeInstanceCount}";
}

尝试类似:

using System;
using System.Threading;

public class HelloWorld
{
    private static int safeInstanceCount = 0;
    
    public static void Main(string[] args)
    {
        long uniqueNumber;
        string str;
        for(int a=0;a<15;a++) {
            Interlocked.Increment(ref safeInstanceCount);
            uniqueNumber  = long.Parse(DateTime.Now.ToString("yyMMddHHmmss"));
            str = $"ENR-{uniqueNumber}{safeInstanceCount}";
            Console.WriteLine (str);
        }
    }
}

上述代码的结果将是:

或者另一个例子可以是:

using System;
using System.Threading;
using System.Linq;

public class HelloWorld
{
    private static int safeInstanceCount = 0;
    private static Random random = new Random();

    public static string RandomString(int length)
    {
        const string chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        return new string(Enumerable.Repeat(chars, length)
            .Select(s => s[random.Next(s.Length)]).ToArray());
    }
    
    public static void Main(string[] args)
    {
        string uniqueNumber;
        string str;
        for(int a=0;a<15;a++) {
            Interlocked.Increment(ref safeInstanceCount);
            uniqueNumber  = RandomString(4);
            str = $"ENR-{uniqueNumber}{safeInstanceCount}";
            Console.WriteLine (str);
        }
    }
}

但是这个例子有可能创建重复的值,如果 应用程序重新启动,因为它将重置静态变量 “safeInstanceCount”回到 0。

您还可以在这里测试代码: https://www.programiz.com/csharp-programming/online-compiler/


-1
投票

可以使用此属性,但要支付 1ms,这并不重要!

public static long UniqId { 
    get { 
        Thread.Sleep(1); 
        return long.Parse(DateTime.Now.ToString("yyMMddHHmmssffff")); 
    } 
}

-1
投票

我正在使用基于时间的简单生成 ID,它可能会有所帮助。

private static readonly string prefixNumber = ConfigManager.Current.GetAppSetting("AppTimeIdPrefix", "");
private static readonly DateTime epoch = DateTime.SpecifyKind(DateTime.Parse(ConfigManager.Current.GetAppSetting("AppTimeIdEpoch", "1970/01/01")), DateTimeKind.Utc);
/// <summary>
/// DateTime.Now is only updated every 10-15ms.
/// </summary>
private static long lastTime = CurrentTimeMilliseconds();
private static readonly object timeLock = new object();

private static long CurrentTimeMilliseconds()
{
   return (long)(DateTime.UtcNow.ToUniversalTime() - epoch).TotalMilliseconds;
}

public static long CreateId()
{
    lock (timeLock)
    { // prevent concurrent access to ensure uniqueness
        long original, newValue;
       do
      {
         original = lastTime;
         newValue = Math.Max(CurrentTimeMilliseconds(), original + 1);
      } while (Interlocked.CompareExchange(ref lastTime, newValue, original) != original);

        return long.Parse(string.Format("{0}{1}", prefixNumber, newValue));
     }
}

参考如何保证时间戳始终唯一?

© www.soinside.com 2019 - 2024. All rights reserved.