I am trying to generate unique values in c# with the help of DateTime ticks and and incrementing number.
Pseudo code:
- Take last 43 significant bits from DateTime.Now ticks (lets name it A)
- Take last 21 bits from increasing sequence (lets name it ‘B’)
- Left shift ‘A’ 21 times (lets name it ‘C’)
- Do binary OR in A and C
I ran the test for generating 2 million number and inserting in database column which has unique constraint set and it ran successfully.
Here is the piece of code that does that:
private static long _sequence = 1;
public static long GetUniqueNumber()
{
const int timeShift = 21;
var dateTime = DateTime.Now.Ticks;
const long dateTimeMask = ~(0L) >> timeShift;
const long sequenceMask = ((~(0L) >> (64 - timeShift)));
var seq = Interlocked.Increment(ref _sequence);
var dateTimeNo = (dateTimeMask & dateTime) << timeShift;
var seqNum = (seq & sequenceMask);
var num = dateTimeNo | seqNum;
return num;
}
I have two questions:
1. Is this logic good enough to generate unique numbers ?
2. I find that some generated numbers are ‘-ve’ which I didn’t understand.
Any help/suggestions/improvements are welcome.
Unique across what scope? Across multiple computers/processes/
AppDomains?, certainly not. Within a singleAppDomain? Not really. Generating 2 million numbers is irrelevant – that’s just testing that your sequence part works. (221 is just over 2 million.)If you can call
GetUniqueNumber221+1 times within the granularity ofDateTime.Now(which is likely to be ~10-15ms) then you’ll get a repeat. Have you measured how fast your computed can call this?Then there’s the fact that those 43 bits will be repeated in 243 ticks’ time… or at least would be if you had a sufficiently fine-grained clock. (And sooner or later the granularity will work against you.)
Whenever
dateTimeNohas its top bit (out of 43) set, you’ll end up with alongwith the top bit set – which means it’ll be negative.EDIT: Also note that your shifting is broken. This:
is performed a sign-extended shift – so you’re just ending up with ~0L.
In short: use
Guid.NewGuid. It’s what it’s there for.