The following snippet
[DllImport("winmm.dll", EntryPoint = "timeBeginPeriod")]
public static extern uint TimeBeginPeriod(uint uMilliseconds);
static void Main(string[] args)
{
if (TimeBeginPeriod(1) != 0)
Console.WriteLine("TimeBeginPeriod failed!");
Console.WriteLine("Sleep");
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < 10; i++)
{
Thread.Sleep(1);
Console.WriteLine(sw.ElapsedTicks * 1000d / Stopwatch.Frequency);
sw.Restart();
}
Console.WriteLine("Threading.Timer");
sw = null;
System.Threading.Timer t = null;
int n = 0;
t = new Timer(state =>
{
if (sw == null)
sw = Stopwatch.StartNew();
else
{
Console.WriteLine(sw.ElapsedTicks * 1000d / Stopwatch.Frequency);
n++;
sw.Restart();
}
if (n == 10)
t.Change(Timeout.Infinite, Timeout.Infinite);
}, null, TimeSpan.FromMilliseconds(1), TimeSpan.FromMilliseconds(1));
Console.ReadKey();
}
will produce e.g. this output:
Sleep
0.151834939915548
0.757358826331279
0.786901687225611
0.712520725399457
0.715593741662697
0.798704863327602
0.5724889615859
0.648825479215934
0.436927039609783
0.517873081634677
Threading.Timer
15.5841035662354
14.8620145856526
15.1098812837944
14.4202684978119
15.3883384620112
14.7210748852159
15.307462261265
15.7125416777831
14.5991320125882
15.6035194417168
According to the net, e.g. a comment by Hans Passant, timeBeginPeriod affects the regular (.net) timers. So why does my timer still have this coarse granularity? Thread.Sleep seems to do just fine.
Maybe relevant: This runs on Windows 7, 64bit, .net 4, inside VMWare.
解决方案
The comment is wrong. My experience has been that the multimedia timer does not affect the .NET timers. That is, it doesn't change their minimum supported time period, which appears to be about 15 ms. It might improve their accuracy. That is, if you ask for 16 ms, you might actually get 16 ms and not "somewhere between 15 and 30 ms."
Why the .NET timers are limited to 15 ms is not clear to me.
There's some information about it in the accepted answer here.
If you're looking for a higher resolution timer for .NET, you probably shouldn't use the multimedia timers. Those have been deprecated in the Windows API. Use the Timer Queue Timers. See my articles:
Another option is to use the Waitable Timer. Full source for that is available at http://www.mischel.com/pubs/waitabletimer.zip