在日常的开发过程中,经常 会使用一些定时器做定时循环处理任务;
C# 中的定时器 包括 WinForm 中的System.Windows.Forms.Timer ;System.Timers.Timer ;System.Threading.Timer;
以上方法在实际运行中,在执行一段时间后都会或多或少出现时间精度丢失的情况。
经过测试:System.Windows.Forms.Timer 每各1秒钟要丢失15毫秒左右;
System.Timers.Timer timer = new System.Timers.Timer();
timer.Elapsed += timer_Elapsed;
timer.Interval = 1000;
timer.AutoReset = true;
timer.Enabled = true;
System.Threading.Timer 每各1秒钟要丢失12~24毫秒左右;
System.Threading.Timer timer2;
TimerCallback timerDelegate = new TimerCallback(timer2_Elapsed);
//创建一个时间间隔为1s的定时器
timer2 = new System.Threading.Timer(timerDelegate, null, 1000, 1000);
这样子的情况就会导致,原计划每分钟运行60次的,可能运行1分钟后,就会少于60次的情况;
因此在网上找了一个利用系统的Kernel32.dll 的QueryPerformanceCounter提高定时精度的手动封装的计时器;
测试的结果如下,基本保证在毫秒级;
调用方法和System.Windows.Forms.Timer的方法差不多,具体如下:
// 方法3:启动HighAccurateTimer 定时器
HighAccurateTimer timer3 = new HighAccurateTimer();
timer3.Interval = 1000;
timer3.Elapsed += new HighTimerEventHandler(timer3_Elapsed);
timer3.Enabled = true;
// 停止定时器
timer3.Enabled = false;
timer3.Destroy();
HighAccurateTimerHelper 封装的代码如下:
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Runtime.InteropServices;
namespace HighAccurateTimerHelper
{
/// <summary>
/// 定时器委托事件的参数
/// </summary>
public class TimerEventArgs : EventArgs
{
private long clockFrequency;
public long ClockFrequency
{
get { return clockFrequency; }
}
private long previousTickCount;
public long PreviousTickOunt
{
get { return previousTickCount; }
}
private long currentTickCount;
public long CurrentTickCount
{
get { return currentTickCount; }
}
public TimerEventArgs(long clockFreq, long prevTick, long currTick)
{
this.clockFrequency = clockFreq;
this.previousTickCount = prevTick;
this.currentTickCount = currTick;
}
}
/// <summary>
/// 高精度定时器事件委托
/// </summary>
public delegate void HighTimerEventHandler(object sender, TimerEventArgs e);
/// <summary>
/// 高精度定时器,网上找的方法,利用Kernel32的QueryPerformanceCounter提高定时精度
/// </summary>
public class HighAccurateTimer
{
[DllImport("Kernel32.dll")]
private static extern bool QueryPerformanceCounter(out long lpPerformanceCount);
[DllImport("Kernel32.dll")]
private static extern bool QueryPerformanceFrequency(out long lpFrequency);
public event HighTimerEventHandler Elapsed;
Thread thread;
private object threadLock = new object();
private long clockFrequency = 0;
private long intevalTicks = 0;
private long nextTriggerTime = 0;
private int intervalMs;
/// <summary>
/// 定时器间隔
/// </summary>
public int Interval
{
get
{
return intervalMs;
}
set
{
intervalMs = value;
}
}
private bool enable;
/// <summary>
/// 启动定时器标志
/// </summary>
public bool Enabled
{
get
{
return enable;
}
set
{
enable = value;
if (value == true)
{
intevalTicks = (long)(((double)intervalMs / (double)1000) * (double)clockFrequency);
long currTick = 0;
GetTick(out currTick);
nextTriggerTime = currTick + intevalTicks;
}else
{
//Destroy();
}
}
}
/// <summary>
/// 构造函数
/// </summary>
public HighAccurateTimer()
{
if (QueryPerformanceFrequency(out clockFrequency) == false)
{
return;
}
this.intervalMs = 1000;
this.enable = false;
thread = new Thread(new ThreadStart(ThreadProc));
thread.Name = "HighAccuracyTimer";
thread.Priority = ThreadPriority.Highest;
thread.Start();
}
/// <summary>
/// 进程主程序
/// </summary>
private void ThreadProc()
{
long currTime;
GetTick(out currTime);
nextTriggerTime = currTime + intevalTicks;
while (true)
{
while (currTime < nextTriggerTime)
{
GetTick(out currTime); //决定时钟的精度
}
nextTriggerTime = currTime + intevalTicks;
if (Elapsed != null && enable == true)
{
Elapsed(this, new TimerEventArgs(clockFrequency, currTime - intevalTicks, currTime));
}
}
}
/// <summary>
/// 获得当前时钟计数
/// </summary>
/// <param name="currentTickCount">时钟计数</param>
/// <returns>获得是否成功</returns>
public bool GetTick(out long currentTickCount)
{
if (QueryPerformanceCounter(out currentTickCount) == false)
{
return false;
}
else
{
return true;
}
}
/// <summary>
/// 注销定时器
/// </summary>
public void Destroy()
{
enable = false;
thread.Abort();
}
}
}