Я использую временные метки для временного порядка одновременных изменений в моей программе и требую, чтобы каждая временная метка изменения была уникальной. Однако я обнаружил, что просто вызов DateTime.Now
недостаточен, так как он часто возвращает одно и то же значение, если вызов выполняется быстро.
У меня есть некоторые мысли, но ничто не поражает меня как "лучшее" решение этого. Есть ли способ, который я могу написать, который гарантирует, что каждый последующий вызов создает уникальный DateTime
?
Должен ли я использовать для этого другой тип, возможно, длинный int? DateTime
имеет очевидное преимущество: легко интерпретироваться как реальное время, в отличие, скажем, от инкрементного счетчика.
Обновление:. Здесь я закончил кодирование как простое компромиссное решение, которое по-прежнему позволяет использовать DateTime
в качестве моего временного ключа, обеспечивая при этом уникальность при каждом вызове метода:
private static long _lastTime; // records the 64-bit tick value of the last time
private static object _timeLock = new object();
internal static DateTime GetCurrentTime() {
lock ( _timeLock ) { // prevent concurrent access to ensure uniqueness
DateTime result = DateTime.UtcNow;
if ( result.Ticks <= _lastTime )
result = new DateTime( _lastTime + 1 );
_lastTime = result.Ticks;
return result;
}
}
Поскольку каждое значение галочки составляет только одну 10-миллионную секунду, этот метод вводит заметное перекос часов при вызове порядка 10 миллионов раз в секунду (что, кстати, достаточно эффективно для выполнения), что означает, что это вполне приемлемо для моих целей.
Вот несколько тестовых кодов:
DateTime start = DateTime.UtcNow;
DateTime prev = Kernel.GetCurrentTime();
Debug.WriteLine( "Start time : " + start.TimeOfDay );
Debug.WriteLine( "Start value: " + prev.TimeOfDay );
for ( int i = 0; i < 10000000; i++ ) {
var now = Kernel.GetCurrentTime();
Debug.Assert( now > prev ); // no failures here!
prev = now;
}
DateTime end = DateTime.UtcNow;
Debug.WriteLine( "End time: " + end.TimeOfDay );
Debug.WriteLine( "End value: " + prev.TimeOfDay );
Debug.WriteLine( "Skew: " + ( prev - end ) );
Debug.WriteLine( "GetCurrentTime test completed in: " + ( end - start ) );
... и результаты:
Start time: 15:44:07.3405024
Start value: 15:44:07.3405024
End time: 15:44:07.8355307
End value: 15:44:08.3417124
Skew: 00:00:00.5061817
GetCurrentTime test completed in: 00:00:00.4950283
Иными словами, через полсекунды он создал 10 миллионов уникальных временных меток, и конечный результат был только продвинут на полсекунды. В реальных приложениях перекос был бы незаметным.