I realize this is way too far into the micro-optimization area, but I am curious to understand why Calls to DateTime.Now and DateTime.UtcNow are so \"expensive\". I have a s
TickCount
just reads a constantly increasing counter. It's just about the simplest thing you can do.
DateTime.UtcNow
needs to query the system time - and don't forget that while TickCount
is blissfully ignorant of things like the user changing the clock, or NTP, UtcNow
has to take this into account.
Now you've expressed a performance concern - but in the examples you've given, all you're doing is incrementing a counter. I would expect that in your real code, you'll be doing rather more work than that. If you're doing a significant amount of work, that's likely to dwarf the time taken by UtcNow
. Before doing anything else, you should measure that to find out whether you're actually trying to solve a problem which doesn't exist.
If you do need to improve things, then:
FWIW here is some code that NLog uses to get the timestamp for each log message. In this case, the "work" is the actual retrieval of the current time (granted, it happens in the context of probably a much more expensive bit of "work", the logging of a message). NLog minimizes the cost of getting the current time by only getting the "real" time (via DateTime.Now
) if the current tick count is different than the previous tick count. This does not really apply directly to your question, but it is an interesting way to "speed up" current time retrieval.
internal class CurrentTimeGetter
{
private static int lastTicks = -1;
private static DateTime lastDateTime = DateTime.MinValue;
/// <summary>
/// Gets the current time in an optimized fashion.
/// </summary>
/// <value>Current time.</value>
public static DateTime Now
{
get
{
int tickCount = Environment.TickCount;
if (tickCount == lastTicks)
{
return lastDateTime;
}
DateTime dt = DateTime.Now;
lastTicks = tickCount;
lastDateTime = dt;
return dt;
}
}
}
// It would be used like this:
DateTime timeToLog = CurrentTimeGetter.Now;
In the context of your question, you could probably "improve" the performance of your time looping code like this:
private static void MethodA_PrecalcEndTime()
{
int cnt = 0;
var doneTime = DateTime.Now.AddSeconds(1);
var startDT = CurrentTimeGetter.Now;
while (CurrentTimeGetter.Now <= doneTime)
{
cnt++;
}
var endDT = DateTime.Now;
Console.WriteLine("Time Taken: {0,30} Total Counted: {1,20}", endDT.Subtract(startDT), cnt); }
}
If CurrentTimeGetter.Now
is called so frequently that the returned time would be the same many times in a row, only the cost of Environment.TickCount
must be paid. I can't say if it really helps with performance of NLog logging such that you would notice or not.
I don't know that it really helps on your question, or if you even need any help anymore, but I thought that it would serve as an interesting example of leveraging a faster operation (Environment.Ticks
) to potentially speed up a relatively slow operation (DateTime.Now
) in some circumstances.
As far as I can tell, DateTime.UtcNow
(not to be confused with DateTime.Now
, which is much slower) is the fastest way you can get time.
In fact, caching it the way @wageoghe proposes decreases performance signifficantly (in my tests, that were 3.5 times).
In ILSpy, UtcNow looks like this:
[__DynamicallyInvokable]
public static DateTime UtcNow
{
[__DynamicallyInvokable, TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), SecuritySafeCritical]
get
{
long systemTimeAsFileTime = DateTime.GetSystemTimeAsFileTime();
return new DateTime((ulong)(systemTimeAsFileTime + 504911232000000000L | 4611686018427387904L));
}
}
I think, this suggests that the function is inlined by the compiler to achieve maximum speed. There might be faster ways to get time, but so far, I haven't seen one
For an up-to-date look on the profiled speed of DateTime.UtcNow
/ DateTimeOffset.UtcNow
, see this dotnet thread, where BenchmarkDotNet
was used to profile.
There was unfortunately a perf regression with the jump to .NET (Core) 3 compared to 2.2, but even reporting with the regressed value, DateTime.UtcNow
is coming in at a pretty rocking time of 71 ns
(it had been 25 ns
), i.e. 71 billionths of a second.
To put that in perspective, even at the slower speed of 71ns
, it means:
You can call DateTime.UtcNow
~ 14,000 times for a cost of only 1 millisecond!
At the previously faster time of 25 ns
(hopefully they will get this performance back), you can call DateTime.UtcNow
~ 40,000 times for a cost of 1 millisecond.
I'm not looking at old .NET Framework times here, but at least with the newer bits, I think it can safely be stated that it is at least no longer accurate to say that DateTime.UtcNow
is "slow/expensive" (I appreciate that the question was asked however!).