zoukankan      html  css  js  c++  java
  • 以当前时间作为GUID的方法

      在C#中,系统提供了GUID类,用户可以通过该类来获得128位的唯一标识,但是该标识不具有可读性,很难把该GUID显示在界面上,以当前时间精确到毫秒来作为GUID是一个比较不错的做法,但是DateTime.now的误差是100ms左右,无法在毫秒级的并发情况下获得不同的时间。

      在项目中,为了在界面上面显示时间相关的单号,是使用Datetime.now.ToString("yyyyMMddHHmmssfff"),结果在毫秒级多次调用该函数的时候,发现获得的字符串居然是一样的。在晚上查了一下,DateTime.now是有误差的,误差是100ms左右。没有很好的获得毫秒级时间的方法,我的想法是在该字符串后面加上个标识来使该字符串变得“唯一”。每次调用该方法时,该标识+1。去掉年份的4位,在后面加上该标识,从而保持获得的id依旧是17位。当该标识==9999时,将其重置为0。这样就可以获得一个唯一的时间相关的字符串了。类似这样:

      

    datetime.now.ToString()+(flag++) .ToString();
    
    if (flag >= 9999) flag = 0;

      在并发的情况下,需要使+(flag++)原子化,如下:

    static int flag = 0;
    static  object o = new object();
    public static string GetTimeGuid(){
        int pFlag = 0;
        Monitor.Enter(o);
        if (flag++>=9999) flag = 0;
        pFlag = flag;
        Monitor.Exit(o);
        return DateTime.Now.ToString("MMddHHmmssfff")+pFlag.ToString();
    }

      值得注意的是,返回的字符串中是访问的局部变量pFlag而不是flag,因为此时已经不在Monitor里面了,无法保证flag是否只执行过一次++操作。我没有在此处使用interlock中的方法,是因为无法做到既flag++且读取flag的值并判断flag是否大于9999这三步操作的整体的原子性,只能使用锁。开始我担心锁会造成过多的性能损耗,因此对该方法进行了测试,

    static void Main(string[] args)
    {
        var array = new string[100];
        var taskArray = new Task[100];
        var stopwatch = new Stopwatch();
        for (var i = 0; i < 100; i++)
        {
            var p = i;
            Action ac = () => array[p] = GetTimeGuid();
            taskArray[p] = new Task(ac);
        }
        stopwatch.Start();
        foreach (var t in taskArray)
        {
            t.Start();
        }
        var factory = new TaskFactory();
        factory.ContinueWhenAll(taskArray, t => {
            stopwatch.Stop();
            long time1, time2;
            time1 = stopwatch.ElapsedMilliseconds;
            foreach (var item in array)
            {
                Console.WriteLine(item);
            }
            for (var i = 0; i < 100; i++)
            {
                var p = i;
                Action ac = () => array[p] = DateTime.Now.ToString("yyyyMMddHHmmssfff");
                taskArray[p] = new Task(ac);
            }
            stopwatch = new Stopwatch();
            stopwatch.Start();
            foreach (var task in taskArray)
            {
                task.Start();
            }
            factory.ContinueWhenAll(taskArray, n =>
            {
                stopwatch.Stop();
                time2 = stopwatch.ElapsedMilliseconds;
                foreach (var item in array)
                {
                    Console.WriteLine(item);
                }
                Console.WriteLine($"{time1},{time2}");
            });
        });
    
        Console.Read();
    }

        这段代码我在我的老旧笔记本上面和台式机上面跑,结果相差非常大,台式机上面只差5ms以内,但是在笔记本上面要差10倍以上。

        本文介绍了一种将时间作为GUID的方法,欢迎在评论区和我讨论。

  • 相关阅读:
    Java实现各种内部排序算法
    Java实现堆排序(大根堆)
    Java对象的序列化和反序列化
    Java实现链式存储的二叉查找树(递归方法)
    337. House Robber III(包含I和II)
    318. Maximum Product of Word Lengths
    114. Flatten Binary Tree to Linked List
    106. Construct Binary Tree from Inorder and Postorder Traversal
    105. Construct Binary Tree from Preorder and Inorder Traversal
    96. Unique Binary Search Trees(I 和 II)
  • 原文地址:https://www.cnblogs.com/jazzpop/p/9344748.html
Copyright © 2011-2022 走看看