How to ensure a timestamp is always unique?

后端 未结 6 564
夕颜
夕颜 2020-12-01 00:18

I\'m using timestamps to temporally order concurrent changes in my program, and require that each timestamp of a change be unique. However, I\'ve discovered that simply call

相关标签:
6条回答
  • 2020-12-01 00:51

    Er, the answer to your question is that "you can't," since if two operations occur at the same time (which they will in multi-core processors), they will have the same timestamp, no matter what precision you manage to gather.

    That said, it sounds like what you want is some kind of auto-incrementing thread-safe counter. To implement this (presumably as a global service, perhaps in a static class), you would use the Interlocked.Increment method, and if you decided you needed more than int.MaxValue possible versions, also Interlocked.Read.

    0 讨论(0)
  • 2020-12-01 00:53

    DateTime.Now is only updated every 10-15ms.

    Not a dupe per se, but this thread has some ideas on reducing duplicates/providing better timing resolution:

    How to get timestamp of tick precision in .NET / C#?

    That being said: timestamps are horrible keys for information; if things happen that fast you may want an index/counter that keeps the discrete order of items as they occur. There is no ambiguity there.

    0 讨论(0)
  • 2020-12-01 00:58

    It can't be guaranteed to be unique, but is perhaps using ticks is granular enough?

    A single tick represents one hundred nanoseconds or one ten-millionth of a second. There are 10,000 ticks in a millisecond.

    0 讨论(0)
  • 2020-12-01 01:01

    I find that the most foolproof way is to combine a timestamp and an atomic counter. You already know the problem with the poor resolution of a timestamp. Using an atomic counter by itself also has the simple problem of requiring its state be stored if you are going to stop and start the application (otherwise the counter starts back at 0, causing duplicates).

    If you were just going for a unique id, it would be as simple as concatenating the timestamp and counter value with a delimiter between. But because you want the values to always be in order, that will not suffice. Basically all you need to do is use the atomic counter value to add addition fixed width precision to your timestamp. I am a Java developer so I will not be able to provide C# sample code just yet, but the problem is the same in both domains. So just follow these general steps:

    1. You will need a method to provide you with counter values cycling from 0-99999. 100000 is the maximum number of values possible when concatenating a millisecond precision timestamp with a fixed width value in a 64 bit long. So you are basically assuming that you will never need more than 100000 ids within a single timestamp resolution (15ms or so). A static method, using the Interlocked class to provide atomic incrementing and resetting to 0 is the ideal way.
    2. Now to generate your id you simply concatenate your timestamp with your counter value padded to 5 characters. So if your timestamp was 13023991070123 and your counter was at 234 the id would be 1302399107012300234.

    This strategy will work as long as you are not needing ids faster than 6666 per ms (assuming 15ms is your most granular resolution) and will always work without having to save any state across restarts of your application.

    0 讨论(0)
  • 2020-12-01 01:03

    One way to get a strictly ascending sequence of timestamps with no duplicates is the following code.

    Compared to the other answers here this one has the following benefits:

    1. The values track closely with actual real-time values (except in extreme circumstances with very high request rates when they would get slightly ahead of real-time).
    2. It's lock free and should perform better that the solutions using lock statements.
    3. It guarantees ascending order (simply appending a looping a counter does not).

    public class HiResDateTime
    {
       private static long lastTimeStamp = DateTime.UtcNow.Ticks;
       public static long UtcNowTicks
       {
           get
           {
               long original, newValue;
               do
               {
                   original = lastTimeStamp;
                   long now = DateTime.UtcNow.Ticks;
                   newValue = Math.Max(now, original + 1);
               } while (Interlocked.CompareExchange
                            (ref lastTimeStamp, newValue, original) != original);
    
               return newValue;
           }
       }
    }
    
    0 讨论(0)
  • 2020-12-01 01:04

    Not sure what you're trying to do entirely but maybe look into using Queues to handle sequentially process records.

    0 讨论(0)
提交回复
热议问题