使用 C# 中自带的各种 timer 计时,都会有累计误差,以下代码实现了一种消除累计误差的方法,使得每次计时的误差,空值在 100 ms 以内(可以通过修改代码提升精度。)

对于精度要求在秒级别的简单计时应用来说,误差可接受,并且消除累计误差。

以下是代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Timers; namespace Xxx.Utils
{
/// <summary>
/// 带有校准功能的秒钟计时器(误差最大100ms)
/// </summary>
public class ClockTimer : IDisposable
{
private readonly Timer _driveTimer;
private int _intervalSeconds = 1;
private double _startMilliSeconds;
private long _tickCount;
private bool _enabled; public ClockTimer()
{
_driveTimer = new Timer(100);
_driveTimer.Elapsed += DriveTimerOnElapsed;
} public ClockTimer(int intervalSeconds) : this()
{
_intervalSeconds = intervalSeconds;
} /// <summary>
/// 获取或设置<see cref="ClockTimer"/>的触发时间间隔,单位:秒。
/// </summary>
public int IntervalSeconds
{
get => _intervalSeconds;
set => _intervalSeconds = value < 1 ? 1 : value;
} /// <summary>
/// 获取或设置一个值,该值指示<see cref="ClockTimer"/>是否引发<see cref="Elapsed"/>事件。
/// </summary>
public bool Enabled
{
get => _enabled;
set
{
if (value)
{
Start();
}
else
{
Stop();
}
}
} /// <summary>
/// 到达时间间隔时发生。
/// </summary>
public event EventHandler<ElapsedEventArgs> Elapsed; /// <summary>
/// 开始计时
/// </summary>
public void Start()
{
_driveTimer.Start();
_enabled = true;
_startMilliSeconds = TimeSpan.FromTicks(DateTime.Now.Ticks).TotalMilliseconds;
} /// <summary>
/// 结束计时
/// </summary>
public void Stop()
{
_driveTimer.Stop();
_tickCount = 0;
_enabled = false;
} private void DriveTimerOnElapsed(object sender, ElapsedEventArgs elapsedEventArgs)
{
double currentMilliseconds = TimeSpan.FromTicks(DateTime.Now.Ticks).TotalMilliseconds; // 第一个 100 ms,直接返回。
if (_tickCount == 0 && Math.Abs(currentMilliseconds - _startMilliSeconds) < 100)
{
return;
} if (Math.Abs(currentMilliseconds - (_startMilliSeconds + (_tickCount + 1) * 1000)) <= 100)
{
_tickCount++;
if (_tickCount % IntervalSeconds == 0)
{
Elapsed?.Invoke(this, elapsedEventArgs);
}
}
} public void Dispose()
{
_driveTimer?.Dispose();
}
}
}

最新文章

  1. 《C标准库》——之&lt;string.h&gt;
  2. UVa12092 Paint the Roads(最小费用最大流)
  3. ScriptManager.RegisterStartupScript
  4. SQLite.net发布后找不到&quot;SQLite.Interop.dll&quot;的问题
  5. 浅谈Redis数据库的键值设计(转)
  6. BestCoder Round #84 Aaronson
  7. 【Python】菜鸟的基本课程继续中
  8. HTTP协议理解
  9. python中去掉空行的问题
  10. Physiological Processes of Speech Production--Reading Notes (8)
  11. 基于visual Studio2013解决C语言竞赛题之0605strcat
  12. Android 程式开发:(廿一)消息传递 —— 21.3 使用Intent发送短信
  13. 创建和关联内容数据库到指定Web应用程序和站点集
  14. Jenkins环境集成第一弹
  15. idea为tomcat设置虚拟地址
  16. 1079. Total Sales of Supply Chain (25) -记录层的BFS改进
  17. Java异常处理最佳实践及陷阱防范
  18. object-fit、object-position 属性
  19. 2017-11-06 日语编程语言&quot;抚子&quot; - 第三版特色初探
  20. stable

热门文章

  1. ios 替换字符串中的部分字符串
  2. 将本地项目和远程git仓库相连接
  3. [洛谷P1029]最大公约数与最小公倍数问题 题解(辗转相除法求GCD)
  4. 在mac上安装ruby
  5. Django之原生Ajax操作
  6. git创建新分支推送到远程
  7. 简单的企业会议管理cms后台模板——后台
  8. 将neuroph导入到Eclipse中
  9. redhat5.5 x64 安装oracle 11g
  10. WebBrowser中运行js