Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why are DateTime.Now DateTime.UtcNow so slow/expensive

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 sample program that runs a couple of scenarios of doing some "work" (adding to a counter) and attempts to do this for 1 second. I have several approached of making it do the work for a limited quantity of time. The examples show that DateTime.Now and DateTime.UtcNow are significantly slower than Environment.TickCount, but even that is slow compared to just letting a separate thread sleep for 1 second and then setting a value to indicate the worker thread to stop.

So my questions are these:

  • I know that UtcNow is faster because it does not have time zone information, why is it still so much slower than TickCount?
  • Why is reading a boolean faster than an int?
  • What is the ideal way of dealing with these types of scenarios where you need to allow something to run for a limited amount of time, but you do not want to waste more time checking the time than actually doing the work?

Please pardon the verbosity of the example:

class Program {     private static volatile bool done = false;     private static volatile int doneInt = 0;     private static UInt64 doneLong = 0;      private static ManualResetEvent readyEvent = new ManualResetEvent(false);      static void Main(string[] args)     {         MethodA_PrecalcEndTime();         MethodB_CalcEndTimeEachTime();         MethodC_PrecalcEndTimeUsingUtcNow();          MethodD_EnvironmentTickCount();          MethodX_SeperateThreadBool();         MethodY_SeperateThreadInt();         MethodZ_SeperateThreadLong();          Console.WriteLine("Done...");         Console.ReadLine();     }      private static void MethodA_PrecalcEndTime()     {         int cnt = 0;         var doneTime = DateTime.Now.AddSeconds(1);         var startDT = DateTime.Now;         while (DateTime.Now <= doneTime)         {             cnt++;         }         var endDT = DateTime.Now;         Console.WriteLine("Time Taken: {0,30} Total Counted: {1,20}", endDT.Subtract(startDT), cnt);     }      private static void MethodB_CalcEndTimeEachTime()     {         int cnt = 0;         var startDT = DateTime.Now;         while (DateTime.Now <= startDT.AddSeconds(1))         {             cnt++;         }         var endDT = DateTime.Now;         Console.WriteLine("Time Taken: {0,30} Total Counted: {1,20}", endDT.Subtract(startDT), cnt);     }      private static void MethodC_PrecalcEndTimeUsingUtcNow()     {         int cnt = 0;         var doneTime = DateTime.UtcNow.AddSeconds(1);         var startDT = DateTime.Now;         while (DateTime.UtcNow <= doneTime)         {             cnt++;         }         var endDT = DateTime.Now;         Console.WriteLine("Time Taken: {0,30} Total Counted: {1,20}", endDT.Subtract(startDT), cnt);     }       private static void MethodD_EnvironmentTickCount()     {         int cnt = 0;         int doneTick = Environment.TickCount + 1000; // <-- should be sane near where the counter clocks...         var startDT = DateTime.Now;         while (Environment.TickCount <= doneTick)         {             cnt++;         }         var endDT = DateTime.Now;         Console.WriteLine("Time Taken: {0,30} Total Counted: {1,20}", endDT.Subtract(startDT), cnt);     }      private static void MethodX_SeperateThreadBool()     {         readyEvent.Reset();         Thread counter = new Thread(CountBool);         Thread waiter = new Thread(WaitBool);         counter.Start();         waiter.Start();         waiter.Join();         counter.Join();     }      private static void CountBool()     {         int cnt = 0;         readyEvent.WaitOne();         var startDT = DateTime.Now;         while (!done)         {             cnt++;         }         var endDT = DateTime.Now;         Console.WriteLine("Time Taken: {0,30} Total Counted: {1,20}", endDT.Subtract(startDT), cnt);     }      private static void WaitBool()     {         readyEvent.Set();         Thread.Sleep(TimeSpan.FromSeconds(1));         done = true;     }      private static void MethodY_SeperateThreadInt()     {         readyEvent.Reset();         Thread counter = new Thread(CountInt);         Thread waiter = new Thread(WaitInt);         counter.Start();         waiter.Start();         waiter.Join();         counter.Join();     }      private static void CountInt()     {         int cnt = 0;         readyEvent.WaitOne();         var startDT = DateTime.Now;         while (doneInt<1)         {             cnt++;         }         var endDT = DateTime.Now;         Console.WriteLine("Time Taken: {0,30} Total Counted: {1,20}", endDT.Subtract(startDT), cnt);     }      private static void WaitInt()     {         readyEvent.Set();         Thread.Sleep(TimeSpan.FromSeconds(1));         doneInt = 1;     }      private static void MethodZ_SeperateThreadLong()     {         readyEvent.Reset();         Thread counter = new Thread(CountLong);         Thread waiter = new Thread(WaitLong);         counter.Start();         waiter.Start();         waiter.Join();         counter.Join();     }      private static void CountLong()     {         int cnt = 0;         readyEvent.WaitOne();         var startDT = DateTime.Now;         while (doneLong < 1)         {             cnt++;         }         var endDT = DateTime.Now;         Console.WriteLine("Time Taken: {0,30} Total Counted: {1,20}", endDT.Subtract(startDT), cnt);     }      private static void WaitLong()     {         readyEvent.Set();         Thread.Sleep(TimeSpan.FromSeconds(1));         doneLong = 1;     }  } 
like image 713
My Other Me Avatar asked Nov 02 '10 06:11

My Other Me


People also ask

How slow is DateTime now?

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!

What is the difference between DateTime now and DateTime UtcNow?

UtcNow tells you the date and time as it would be in Coordinated Universal Time, which is also called the Greenwich Mean Time time zone - basically like it would be if you were in London England, but not during the summer. DateTime. Now gives the date and time as it would appear to someone in your current locale.

How accurate is DateTime now?

Now has an approximate resolution of 10 milliseconds on all NT operating systems. The actual precision is hardware dependent.

What is the difference between DateTime now and DateTime today?

The DateTime. Now property returns the current date and time, for example 2011-07-01 10:09.45310 . The DateTime. Today property returns the current date with the time compnents set to zero, for example 2011-07-01 00:00.00000 .


1 Answers

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:

  • You can use a timer rather than creating a new thread explicitly. There are various kinds of timers in the framework, and without knowing your exact situation, I can't advise on which would be most sensible to use - but it feels like a better solution than starting a thread.
  • You can measure a few iterations of your task, then guess how many will actually be required. You might want to then execute half that many iterations, take stock of how long that's taken, then adjust the number of remaining cycles accordingly. Of course, this doesn't work if the time take per iteration can vary wildly.
like image 76
Jon Skeet Avatar answered Sep 24 '22 12:09

Jon Skeet