是否有一个高分辨率计时器,每次经过计时器后都会引发一个事件,就像System.Timer上课一样?我需要Elapse每毫秒毫秒的高分辨率计时器。
System.Timer
Elapse
我经常遇到一些帖子,它们解释说秒表可以测量高分辨率,但是我不想测量时间,我想创建一个1毫秒的间隔。
.NET中是否有内容,还是我要编写自己的高分辨率计时器?
我所知道的没有内置到.NET框架中。Windows具有通过Multimedia Timer API进行高分辨率计时器事件的机制。下面是一个简单的例子,我似乎可以解决。也有似乎是一个很好的例子在这里。
我将注意,此API会更改系统范围的设置,从而降低系统性能,因此请买家注意。为了进行测试,我建议您跟踪计时器触发的频率,以验证时序是否与您要模拟的设备相似。由于Windows不是实时操作系统,因此系统上的负载可能会导致MM计时器延迟,从而导致100毫秒的间隔,其中包含100个连续快速的事件,而不是间隔1毫秒的100个事件。有关MM计时器的一些其他资料。
class Program { static void Main(string[] args) { TestThreadingTimer(); TestMultimediaTimer(); } private static void TestMultimediaTimer() { Stopwatch s = new Stopwatch(); using (var timer = new MultimediaTimer() { Interval = 1 }) { timer.Elapsed += (o, e) => Console.WriteLine(s.ElapsedMilliseconds); s.Start(); timer.Start(); Console.ReadKey(); timer.Stop(); } } private static void TestThreadingTimer() { Stopwatch s = new Stopwatch(); using (var timer = new Timer(o => Console.WriteLine(s.ElapsedMilliseconds), null, 0, 1)) { s.Start(); Console.ReadKey(); } } } public class MultimediaTimer : IDisposable { private bool disposed = false; private int interval, resolution; private UInt32 timerId; // Hold the timer callback to prevent garbage collection. private readonly MultimediaTimerCallback Callback; public MultimediaTimer() { Callback = new MultimediaTimerCallback(TimerCallbackMethod); Resolution = 5; Interval = 10; } ~MultimediaTimer() { Dispose(false); } public int Interval { get { return interval; } set { CheckDisposed(); if (value < 0) throw new ArgumentOutOfRangeException("value"); interval = value; if (Resolution > Interval) Resolution = value; } } // Note minimum resolution is 0, meaning highest possible resolution. public int Resolution { get { return resolution; } set { CheckDisposed(); if (value < 0) throw new ArgumentOutOfRangeException("value"); resolution = value; } } public bool IsRunning { get { return timerId != 0; } } public void Start() { CheckDisposed(); if (IsRunning) throw new InvalidOperationException("Timer is already running"); // Event type = 0, one off event // Event type = 1, periodic event UInt32 userCtx = 0; timerId = NativeMethods.TimeSetEvent((uint)Interval, (uint)Resolution, Callback, ref userCtx, 1); if (timerId == 0) { int error = Marshal.GetLastWin32Error(); throw new Win32Exception(error); } } public void Stop() { CheckDisposed(); if (!IsRunning) throw new InvalidOperationException("Timer has not been started"); StopInternal(); } private void StopInternal() { NativeMethods.TimeKillEvent(timerId); timerId = 0; } public event EventHandler Elapsed; public void Dispose() { Dispose(true); } private void TimerCallbackMethod(uint id, uint msg, ref uint userCtx, uint rsv1, uint rsv2) { var handler = Elapsed; if (handler != null) { handler(this, EventArgs.Empty); } } private void CheckDisposed() { if (disposed) throw new ObjectDisposedException("MultimediaTimer"); } private void Dispose(bool disposing) { if (disposed) return; disposed = true; if (IsRunning) { StopInternal(); } if (disposing) { Elapsed = null; GC.SuppressFinalize(this); } } } internal delegate void MultimediaTimerCallback(UInt32 id, UInt32 msg, ref UInt32 userCtx, UInt32 rsv1, UInt32 rsv2); internal static class NativeMethods { [DllImport("winmm.dll", SetLastError = true, EntryPoint = "timeSetEvent")] internal static extern UInt32 TimeSetEvent(UInt32 msDelay, UInt32 msResolution, MultimediaTimerCallback callback, ref UInt32 userCtx, UInt32 eventType); [DllImport("winmm.dll", SetLastError = true, EntryPoint = "timeKillEvent")] internal static extern void TimeKillEvent(UInt32 uTimerId); }