Я использую временные метки для временного упорядочения параллельных изменений в моей программе и требую, чтобы каждая временная метка изменения была уникальной.Однако я обнаружил, что простого вызова DateTime.Now
недостаточно, поскольку он часто возвращает одно и то же значение, если вызывается в быстрой последовательности.
У меня есть некоторые мысли, но ничто не кажется мне "лучшим" решениемк этому.Могу ли я написать метод, который будет гарантировать, что каждый последующий вызов выдаст уникальный DateTime
?
Должен ли я использовать для этого другой тип, например long 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 миллионов уникальных временных меток и окончательнуюрезультат опередил только на полсекунды.В реальных приложениях перекос был бы незаметен.