文章转至:http://www.codeproject.com/Articles/98346/Microsecond-and-Millisecond-NET-Timer

Introduction
Anyone who has used the .NET System.Timers.Timer class for low interval times will realise that it does not offer a very high resolution. The resolution will be system dependant, but a maximum resolution is usually around 15ms (System.Windows.Forms.Timer has an even worse resolution, although it is unlikely a UI will need to be updated this fast). Significantly better performance can be achieved using the Win32 multimedia timer (there are various .NET projects that wrap this timer); however, there are no timers available in the microsecond range.

The problem I encountered was that I needed to send an Ethernet UDP message packet out every 800µs (0.8ms); it did not matter if a packet was slightly delayed or did not go off exactly 800µs after the last one. Basically, what I needed was a microsecond timer that was accurate the majority of the time.

The fundamental problem with a software timer in the region of 1ms is that Windows is a non real-time Operating System (RTOS) and is not suitable for generating regular and accurate events around the 1ms mark. MicroTimer cannot and does not solve this problem; however, it does offer a microsecond timer which offers a reasonable degree of accuracy (approx. 1µs) the majority (approx. 99.9%) of the time. The trouble is, the 0.1% of the time, the timer can be very inaccurate (whilst the Operating System gives some of the processing time to other threads and processes). The accuracy is highly system/processor dependant; a faster system will result in a more accurate timer.

The beauty of MicroTimer is that it is called in a very similar way to the existing System.Timers.Timer class; however, the interval is set in microseconds (as opposed to milliseconds in System.Timers.Timer). On each timed event, MicroTimer invokes the predefined (OnTimedEvent) callback function. The MicroTimerEventArgs properties provide information (to the microsecond) on when exactly (and how late) the timer was invoked.
Using the code

'MicroLibrary.cs' encompasses three classes (under the namespace MicroLibrary):

MicroStopwatch - This derives from and extends the System.Diagnostics.Stopwatch class; importantly, it provides the additional property ElapsedMicroseconds. This is useful as a standalone class where the elapsed microseconds from when the stopwatch was started can be directly obtained.
    MicroTimer - Designed so it operates in a very similar way to the System.Timers.Timer class, it has a timer interval in microseconds and Start / Stop methods (or Enabled property). The timer implements a custom event handler (MicroTimerElapsedEventHandler) that fires every interval. The NotificationTimer function is where the 'work' is done and is run in a separate high priority thread. It should be noted that MicroTimer is inefficient and very processor hungry as the NotificationTimer function runs a tight while loop until the elapsed microseconds is greater than the next interval. The while loop uses a SpinWait, this is not a sleep but runs for a few nanoseconds and effectively puts the thread to sleep without relinquishing the remainder of its CPU time slot. This is not ideal; however, for such small intervals, this is probably the only practical solution.
    MicroTimerEventArgs - Derived from System.EventArgs, this class provides an object for holding information about the event. Namely, the number of times the event has fired, the absolute time (in microseconds) from when the timer was started, how late the event was and the execution time of the callback function (for the previous event). From this data, a range of timer information can be derived.

By design, the amount of work done in the callback function (OnTimedEvent) must be small (e.g. update a variable or fire off a UDP packet). To that end, the work done in the callback function must take significantly less time than the timer interval. Separate threads could be spawned for longer tasks; however, this goes outside the scope of this article. As discussed earlier, because Windows is not a real time Operating System, the callback function (OnTimedEvent) may be late; if this happens and any particular interval is delayed, there are two options:

Either: Set the property IgnoreEventIfLateBy whereby the callback function (OnTimedEvent) will not be called if the timer is late by the specified number of microseconds. The advantage of this is the timer will not attempt to 'catch up', i.e., it will not call the callback function in quick succession in an attempt to catch up. The disadvantage is that some events will be missed.
    Or: By default, MicroTimer will always try and catch up on the next interval. The advantage of this is the number of times the OnTimeEvent is called will always be correct for the total elapsed time (which is why the OnTimedEvent must take significantly less time than the interval; if it takes a similar or longer time, MicroTimer can never 'catch up' and the timer event will always be late). The disadvantage of this is when it's trying to 'catch up', the actual interval achieved will be much less than the required interval as the callback function is called in quick succession in an attempt to catch up.

The timer may be stopped in one of three ways:

Stop (or Enabled = false) - This method stops the timer by setting a flag to instruct the timer to stop, however, this call executes asynchronously i.e. the call to Stop will return immediately (but the current timer event may not have finished).
    StopAndWait - This method stops the timer synchronously, it will not return until the current timer (callback) event has finished and the timer thread has terminated. StopAndWait also has an overload method that accepts a timeout (in ms), if the timer successfully stops within the timeout period then true is returned, else false is returned.
    Abort - This method may be used as a last resort to terminate the timer thread, for example, to abort the timer if it has not stopped after waiting 1sec (1000ms) use:
    if( !microTimer.StopAndWait(1000) ){ microTimer.Abort(); }

The code below shows the MicroLibrary namespace (MicroLibrary.cs) which contains the three classes, MicroStopwatch, MicroTimer and MicroTimerEventArgs. See the 'Download source' link above.

The code below shows a very simple (console application) implementation of the MicroTimer class with the interval set to 1,000µs (1ms). See the 'Download Console demo project' link above.

The screenshot below shows the console output. The performance varies on different runs, but was usually accurate to 1µs. Due to system caching, the accuracy was worse on the first run and got better after the first few events. This test was on a 2GHz Dell Inspiron 1545 with an Intel Core 2 Duo (running Windows 7 64bit). The performance improved significantly on faster machines.

It is very unlikely a UI will need to be updated at intervals in the millisecond range. Purely for the point of demonstration, the 'Download WinForms demo project' link above contains a very simple WinForms application that updates a UI using the MicroTimer. The screenshot below demonstrates the application acting as a stopwatch (with a microsecond display) where the UI is being updated with the ElapsedMicroseconds every 1111µs (1.111ms).

Summary

MicroTimer is designed for situations were a very quick timer is required (around the 1ms mark); however, due to the non real-time nature of the Windows Operating System, it can never be accurate. However, as no other microsecond software timers are available, it does offer a reasonable solution for this task (and although processor hungry, is reasonably accurate on fast systems).

Microsecond and Millisecond C# Timer[转]的更多相关文章

  1. Timer

    timer类有三种 1.System.Windows.Forms.Timer  使用地方:Windows 窗体应用程序中,并且必须在窗口中使用.  2.System.Timers.Timer 使用地方 ...

  2. golang的timer一些坑

    本文代码部分基于dive-to-gosync-workshop的代码 Golang 的NewTimer方法调用后,生成的timer会放入最小堆,一个后台goroutine会扫描这个堆,将到时的time ...

  3. go标准库的学习-time

    参考https://studygolang.com/pkgdoc 导入形式: import "time" time包提供了时间的显示和测量用的函数.日历的计算采用的是公历. 1&g ...

  4. Managed Media Aggregation using Rtsp and Rtp

    his article was written almost 2 years ago, it's content may not reflect the latest state of the cod ...

  5. Go语言基础之3--时间和日期序列

    一.时间和日期类型 1. time包 2. time.Time类型,用来表示时间 3. 获取当前时间, now := time.Now() 实例1-1  打印输出当前时间 package main i ...

  6. 关于golang的time包总结

    目录 前言 time包详解 总结 前言 各种编程语言都少不了与时间有关的操作,因为很多判断都是基于时间,因此正确和方便的使用时间库就很重要额. golang提供了import "time&q ...

  7. PHP获取毫秒时间戳,利用microtime()函数

    PHP获取毫秒时间戳,利用microtime()函数 php本身没有提供返回毫秒数的函数,但提供了一个microtime()函数,借助此函数,可以很容易定义一个返回毫秒数的函数.php的毫秒是没有默认 ...

  8. PHP获取当前时间的毫秒数(yyyyMMddHHmmssSSS)

    1 second = 1000 millisecond = 1000,000 microsecond = 1000,000,000 nanosecond php的毫秒是没有默认函数的,但提供了一个mi ...

  9. .NETCore 新型 ORM 功能介绍

    简介 FreeSql 是一个功能强大的 .NETStandard 库,用于对象关系映射程序(O/RM),支持 .NETCore 2.1+ 或 .NETFramework 4.6.1+. 定义 IFre ...

随机推荐

  1. VC++ 学习笔记(序):神一样的语言

    总的来说,我觉得VC++是一门神一样的语言——它是公认最强大.最复杂的:它一切以效率为第一要务,却又不肯落伍,拼命兼容现在的新的语言设计特点.本来在别的语言很容与就避开的问题,在这里要用很高的技巧去设 ...

  2. 为MFC界面添加一个Log Window

    前言 由于早期的图像处理程序基于VC6.0,MFC也是采用VC6.0开发的.在实际处理中,我不仅需要界面的显示,有很多时候,我需要算法处理的过程中的信息,比如每个阶段的耗时,处理的图像大小,以及如果需 ...

  3. Android实现自适应正方形GridView(陌陌引导页面效果)

    1.http://blog.chengyunfeng.com/?p=465 2.备注,慢慢研究

  4. Java Bytecode Instructions List

    monic Opcode(in hex) Other bytes Stack[before]→[after] Description aaload 32   arrayref, index → val ...

  5. Shooting Algorithm

    Shooting算法是Wenjiang提出的一种优化Lasso(L1 Regularization)和Bridge Regression的算法, 本文以Lasso为例. 对于线性回归问题$\mathb ...

  6. Qt编写自定义控件插件路过的坑及注意事项

    在一日一控件的口号下,终于写好了五十几个自定义控件,包括各种仪表盘,各种温度计,各种进度条,各种按钮等,具体可参见(http://www.cnblogs.com/feiyangqingyun/p/61 ...

  7. 二十六、【开源框架】EFW框架Winform前端开发之Grid++Report报表、条形码、Excel导出、图表控件

    回<[开源]EFW框架系列文章索引>        EFW框架源代码下载V1.2:http://pan.baidu.com/s/1hcnuA EFW框架实例源代码下载:http://pan ...

  8. Android 使用版本控制工具时添加忽略文件方式

    一.使用SVN管理项目时,添加忽略文件的方式 Android Studio 配合SVN时,添加忽略文件相对简单,首先打开项目的Settings选项,切换到Version Control下的Ignore ...

  9. 推荐一款炫酷的提示框插件SweetAlert

    官方网址 http://t4t5.github.io/sweetalert/ 项目地址 https://github.com/t4t5/sweetalert

  10. codeforces C. Bits(数学题+或运算)

    题意:给定一个区间,求区间中的一个数,这个数表示成二进制的时候,数字1的个数最多! 如果有多个这样的数字,输出最小的那个! 思路:对左区间的这个数lx的二进制 从右往左将0变成1,直到lx的值大于右区 ...