How frequent is DateTime.Now updated ? or is there a more precise API to get the current time?
I have code running in a loop and it's saving state based on the current time. Sometimes this can be just milliseconds apart, but for some reason it seems that DateTime.Now will always return values of at least 10 ms apart even if it's only 2 or 3 ms later. This presents a major problem since the state i'm saving depends on the time it was saved (eg recording something)
My test code that returns each value 10 ms apart:
public static void Main()
{
var dt1 = DateTime.Now;
System.Threading.Thread.Sleep(2);
var dt2 = DateTime.Now;
// On my machine the values will be at least 10 ms apart
Console.WriteLine("First: {0}, Second: {1}", dt1.Millisecond, dt2.Millisecond);
}
Is there another solution on how to get the accurate current time up to the millisecond ?
Someone suggested to look at the Stopwatch class. Although the Stopwatch class is very accurate it does not tell me the current time, something i need in order to save the state of my program.
Curiously, your code works perfectly fine on my quad core under Win7, generating values exactly 2 ms apart almost every time.
So I've done a more thorough test. Here's my example output for Thread.Sleep(1)
. The code prints the number of ms between consecutive calls to DateTime.UtcNow
in a loop:
Each row contains 100 characters, and thus represents 100ms of time on a "clean run". So this screen covers roughly 2 seconds. The longest preemption was 4ms; moreover, there was a period lasting around 1 second when every iteration took exactly 1 ms. That's almost real-time OS quality!1 :)
So I tried again, with Thread.Sleep(2)
this time:
Again, almost perfect results. This time each row is 200ms long, and there's a run almost 3 seconds long where the gap was never anything other than exactly 2ms.
Naturally, the next thing to see is the actual resolution of DateTime.UtcNow
on my machine. Here's a run with no sleeping at all; a .
is printed if UtcNow
didn't change at all:
Finally, while investigating a strange case of timestamps being 15ms apart on the same machine that produced the above results, I've run into the following curious occurrences:
There is a function in the Windows API called timeBeginPeriod
, which applications can use to temporarily increase the timer frequency, so this is presumably what happened here. Detailed documentation of the timer resolution is available via the Hardware Dev Center Archive, specifically Timer-Resolution.docx (a Word file).
Conclusions:
DateTime.UtcNow
can have a much higher resolution than 15ms Thread.Sleep(1)
can sleep for exactly 1ms UtcNow
grows grow by exactly 1ms at a time (give or take a rounding error - Reflector shows that there's a division in UtcNow
). Here's the code:
static void Main(string[] args)
{
Console.BufferWidth = Console.WindowWidth = 100;
Console.WindowHeight = 20;
long lastticks = 0;
while (true)
{
long diff = DateTime.UtcNow.Ticks - lastticks;
if (diff == 0)
Console.Write(".");
else
switch (diff)
{
case 10000: case 10001: case 10002: Console.ForegroundColor=ConsoleColor.Red; Console.Write("1"); break;
case 20000: case 20001: case 20002: Console.ForegroundColor=ConsoleColor.Green; Console.Write("2"); break;
case 30000: case 30001: case 30002: Console.ForegroundColor=ConsoleColor.Yellow; Console.Write("3"); break;
default: Console.Write("[{0:0.###}]", diff / 10000.0); break;
}
Console.ForegroundColor = ConsoleColor.Gray;
lastticks += diff;
}
}
It turns out there exists an undocumented function which can alter the timer resolution. I haven't investigated the details, but I thought I'd post a link here: NtSetTimerResolution
.
1Of course I made extra certain that the OS was as idle as possible, and there are four fairly powerful CPU cores at its disposal. If I load all four cores to 100% the picture changes completely, with long preemptions everywhere.
The problem with DateTime when dealing with milliseconds isn't due to the DateTime class at all, but rather, has to do with CPU ticks and thread slices. Essentially, when an operation is paused by the scheduler to allow other threads to execute, it must wait at a minimum of 1 time slice before resuming which is around 15ms on modern Windows OSes. Therefore, any attempt to pause for less than this 15ms precision will lead to unexpected results.
如果您在做任何事情之前拍摄当前时间的快照,您可以将秒表添加到您存储的时间,不是?
链接地址: http://www.djcxy.com/p/52808.html