返回顶部
首页 > 资讯 > 精选 >如何在C#中创建一个高精度的定时器
  • 233
分享到

如何在C#中创建一个高精度的定时器

2023-06-06 14:06:07 233人浏览 安东尼
摘要

如何在C#中创建一个高精度的定时器?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。1 两个是通用的多线程定时器:System.Threading.TimerSystem

如何在C#中创建一个高精度的定时器?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。

1 两个是通用的多线程定时器:

  • System.Threading.Timer

  • System.Timers.Timer

2 两个是专用的单线程定时器

  • System.windows.FORMs.Timer (Windows Forms 的定时器)

  • System.Windows.Threading.DispatcherTimer (WPF 的定时器)

通常他们的精度只能维持在10-20ms之间,这个和操作系统相关,所以我们在很多场景下面这个是不能够达到我们精度的要求的,如果要实现这一需求我们该怎么办,当然也有很多办法,今天主要介绍一种Stopwatch来实现的方式,网上有很多采用Win32 Dll的api这个当然是可以的,这篇文章的重点不是去讨论这个,关于使用Win32 API的方式可以参考这里。

实现

using System;using System.Collections.Generic;using System.Diagnostics;using System.Linq;using System.Runtime.InteropServices;using System.Text; namespace Pangea.Common.Utility{    /// <summary>    /// .net Stopwatch对高精度定时器作了很好的包装    /// DeviceTimer内部采用Stopwatch类实现高精度定时操作    /// </summary>    public sealed class DeviceTimer    {#if USE_CPU_COUNTING        //引入高性能计数器API,通过对CPU计数完成计时        [DllImport("Kernel32.dll")]        private static extern bool QueryPerformanceCounter(out long lpPerformanceCount);         //获取当前CPU的工作频率        [DllImport("Kernel32.dll")]        private static extern bool QueryPerformanceFrequency(out long lpFrequency);#else        /// <summary>        /// 获取TickCount64计数        /// </summary>        /// <returns></returns>        //[DllImport("kernel32.dll")]        //public static extern long GetTickCount64();#endif        private enum DeviceTimerState        {            TM_ST_IDLE = 0,            TM_ST_BUSY = 1,            TM_ST_TIMEOUT = 2,        }         /// <summary>        /// Stopwatch object        /// </summary>        Stopwatch _stopWatch = new Stopwatch();         /// <summary>        /// 定时器内部状态        /// </summary>        DeviceTimerState _state;         /// <summary>        /// 定时器开始计时时刻的相对时间点        /// </summary>        long _startTime;         /// <summary>        /// 定时器超时时刻的相对时间点        /// </summary>        long _timeOut; #if USE_CPU_COUNTING         /// <summary>        /// CPU运行的时钟频率        /// </summary>        double _freq;#endif         /// <summary>        /// 定时时间(单位:ms)        /// </summary>        double _duration;         /// <summary>        /// class constructure        /// </summary>        public DeviceTimer()        {#if USE_CPU_COUNTING            long freq;            if (QueryPerformanceFrequency(out freq) == false)                throw new Exception("本计算机不支持高性能计数器");            //得到每1ms的CPU计时TickCount数目            _freq = (double)freq / 1000.0;            QueryPerformanceCounter(out _startTime);#else            _stopWatch.Start();            _startTime = 0;#endif            SetState(DeviceTimerState.TM_ST_IDLE);            _timeOut = _startTime;            _duration = 0;        }         /// <summary>        /// 内部调用:设置定时器当前状态        /// </summary>        /// <param name="state"></param>        private void SetState(DeviceTimerState state)        {            _state = state;        }         /// <summary>        /// 内部调用:返回定时器当前状态        /// </summary>        /// <returns></returns>        private DeviceTimerState GetState()        {            return _state;        }         /// <summary>        /// 定时器开始计时到现在已流逝的时间(单位:毫秒)        /// </summary>        /// <returns></returns>        public double GetElapseTime()        {            long curCount;#if USE_CPU_COUNTING            QueryPerformanceCounter(out curCount);            return (double)(curCount - _startTime) / (double)_freq;#else            curCount = _stopWatch.ElapsedMilliseconds;            return curCount - _startTime;#endif        }         /// <summary>        /// 获取定时总时间        /// </summary>        /// <returns></returns>        public double GetTotalTime()        {            return _duration;        }         /// <summary>        /// 停止计时器计时        /// </summary>        public void Stop()        {            SetState(DeviceTimerState.TM_ST_IDLE);#if USE_CPU_COUNTING            QueryPerformanceCounter(out _startTime);#else            _startTime = _stopWatch.ElapsedMilliseconds;#endif            _timeOut = _startTime;            _duration = 0;        }         /// <summary>        /// 启动定时器        /// </summary>        /// <param name="delay_ms">定时时间(单位:毫秒)</param>        public void Start(double delay_ms)        {#if USE_CPU_COUNTING            QueryPerformanceCounter(out _startTime);            _timeOut = Convert.ToInt64(_startTime + delay_ms * _freq);#else            _startTime = _stopWatch.ElapsedMilliseconds;            _timeOut = Convert.ToInt64(_startTime + delay_ms);#endif            SetState(DeviceTimerState.TM_ST_BUSY);            _duration = delay_ms;        }         /// <summary>        /// 重新开始定时器        /// 开始的计时时间以上一次Start的时间为准        /// </summary>        /// <param name="delay_ms">定时时间(单位:毫秒)</param>        public void Restart(double delay_ms)        {#if USE_CPU_COUNTING            _timeOut = Convert.ToInt64(_startTime + delay_ms * _freq);#else            _timeOut = Convert.ToInt64(_startTime + delay_ms);#endif            SetState(DeviceTimerState.TM_ST_BUSY);            _duration = delay_ms;        }         /// <summary>        /// 返回定时器是否超时        /// </summary>        /// <returns></returns>        public bool IsTimeout()        {            if (_state == DeviceTimerState.TM_ST_IDLE)            {                //System.Diagnostics.Debug.WriteLine("Warning: Misuage of the device timer. You must start it first before you can use it.");                //System.Diagnostics.Debug.Assert(false, "Warning: Misuage of the device timer. You must start it first before you can use it.");            }            long curCount;#if USE_CPU_COUNTING            QueryPerformanceCounter(out curCount);#else            curCount = _stopWatch.ElapsedMilliseconds;#endif            if (_state == DeviceTimerState.TM_ST_BUSY && (curCount >= _timeOut))            {                SetState(DeviceTimerState.TM_ST_TIMEOUT);                return true;            }            else if (_state == DeviceTimerState.TM_ST_TIMEOUT)            {                return true;            }            return false;        }         /// <summary>        /// 定时器是否在工作中        /// </summary>        /// <returns></returns>        public bool IsIdle()        {            return (_state == DeviceTimerState.TM_ST_IDLE);        }    }}

  这个里面我们在DeviceTimer中定义了一个私有的_stopWatch 对象并且在构造函数中就启动了这个Stopwatch,所以我们在使用的时候是通过先创建一个DeveiceTimer的对象然后我们再调用内部的Start方法,当然在调用这个方法的时候我们需要传入一个定时时间,然后不断检测IsTimeout方法看是否到达定时时间,从而达到类似于定时时间到的效果,另外GetElapseTime()方法能够获取从调用Start方法开始到现在的时间,另外我们还在其中定义了几个枚举值用来表示当前DeviceTimer的状态用于做一些状态的校验,具体数值如下。

private enum DeviceTimerState{    TM_ST_IDLE = 0,    TM_ST_BUSY = 1,    TM_ST_TIMEOUT = 2,}

  这里还有最后一个问题就是循环调用的问题,这个其实也是非常简单就在一个While循环中不断进行调用,当然下面的代码可以有很多内容供我们去发挥的,这个可以根据自己的需要进行修改。

using System;using System.Threading.Tasks; namespace DeviceTimerConsoleApp{    class Program    {        private static bool flag = true;        static void Main(string[] args)        {            Task.Factory.StartNew(() =>            {                var deviceTimer = new DeviceTimer();                deviceTimer.Start(5);                 while (flag)                {                    if (deviceTimer.IsTimeout())                    {                        Console.WriteLine($"定时时间已到,距离开始执行已过去:{deviceTimer.GetElapseTime()}ms");                         deviceTimer.Start(5);                    }                }            });            Console.ReadKey();        }    }     }

看完上述内容,你们掌握如何在C#中创建一个高精度的定时器的方法了吗?如果还想学到更多技能或想了解更多相关内容,欢迎关注编程网精选频道,感谢各位的阅读!

--结束END--

本文标题: 如何在C#中创建一个高精度的定时器

本文链接: https://lsjlt.com/news/247488.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 如何在C#中创建一个高精度的定时器
    如何在C#中创建一个高精度的定时器?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。1 两个是通用的多线程定时器:System.Threading.TimerSystem...
    99+
    2023-06-06
  • 怎么在C#中创建一个自定义特性
    这期内容当中小编将会给大家带来有关怎么在C#中创建一个自定义特性,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。实现方式声明自定义特性,一个新的自定义特性应派生自 System.Attribute 类。//...
    99+
    2023-06-14
  • 如何在redis中创建一个表
    在redis中创建一个表的方法:在DMS for Data Lake Analytics中创建表dla_person_csv,代码示例:CREATE EXTERNAL TABLE dla_person_csv (id int,name va...
    99+
    2024-04-02
  • 如何在python中创建一个ndarray
    这篇文章将为大家详细讲解有关如何在python中创建一个ndarray,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。python可以做什么Python是一种编程语言,内置了许多有效的工具,P...
    99+
    2023-06-14
  • 如何在Cassandra中创建一个Keyspace
    在Cassandra中创建一个Keyspace可以通过CQL语句来实现。以下是一个简单的示例: CREATE KEYSPACE my...
    99+
    2024-04-02
  • 如何在Linux中创建定时任务
    要在Linux中创建定时任务,可以使用crontab命令。以下是创建定时任务的步骤: 打开终端窗口。 输入以下命令来编辑cr...
    99+
    2024-03-15
    Linux
  • C#中如何创建一个Excel文件
    这篇文章给大家介绍C#中如何创建一个Excel文件,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。C#创建Excel文件实例操作:private void Button2_Click(object&n...
    99+
    2023-06-17
  • 如何在java中创建一个对象
    这篇文章给大家介绍如何在java中创建一个对象,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。Java是什么Java是一门面向对象编程语言,可以编写桌面应用程序、Web应用程序、分布式系统和嵌入式系统应用程序。1、创建对...
    99+
    2023-06-14
  • 如何在TensorFlow中创建一个张量
    在 TensorFlow 中,可以使用 tf.constant() 函数创建一个张量。示例如下: import tensorflow...
    99+
    2024-03-01
    TensorFlow
  • 如何在Zabbix中创建一个主机
    要在Zabbix中创建一个主机,您可以按照以下步骤进行操作: 登录到Zabbix的Web界面。 在左侧导航栏中,找到“配置”选项,...
    99+
    2024-04-09
    Zabbix
  • 如何在Android项目中创建一个自定义控件
    本篇文章为大家展示了如何在Android项目中创建一个自定义控件,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。仿iPhone 的风格,在界面的顶部放置一个标题栏。<&#63;xml v...
    99+
    2023-05-31
    android roi 目中
  • CSS中如何使用Frasbox创建等高度定价表
    本篇文章为大家展示了CSS中如何使用Frasbox创建等高度定价表,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。OneTwoThreeFourFiveSixSeve...
    99+
    2024-04-02
  • 如何在hbuilder中创建一个HTML文件
    小编给大家分享一下如何在hbuilder中创建一个HTML文件,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧! 我使用的是Hbu...
    99+
    2024-04-02
  • 如何在pycharm中创建一个新项目
    如何在pycharm中创建一个新项目?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。操作环境:windows7系统、PyCharm 4.0.3版,DELL G3电脑。pychar...
    99+
    2023-06-07
  • 如何创建一个新的数据库在PostgreSQL中
    要在PostgreSQL中创建一个新的数据库,可以使用以下步骤: 打开命令行界面或者使用图形用户界面工具连接到PostgreSQ...
    99+
    2024-04-09
    PostgreSQL
  • 如何在NiFi中创建一个新的数据流
    要在NiFi中创建一个新的数据流,可以按照以下步骤进行: 打开NiFi的用户界面,登录到NiFi控制台。 在NiFi界面左侧...
    99+
    2024-04-02
  • 如何在eclipse中创建一个spring boot项目
    这期内容当中小编将会给大家带来有关如何在eclipse中创建一个spring boot项目,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。spring Boot是由Pivotal团队提供的全新框架,其设计目...
    99+
    2023-05-31
    eclipse springboot spring boo
  • 如何在Go语言中创建一个必要的包
    如何在Go语言中创建一个必要的包 在Go语言中,包是组织代码的基本单元,它可以包含多个相关的函数、变量和类型定义。创建一个必要的包是每个Go语言程序员都需要掌握的基本技能。本文将演示如...
    99+
    2024-03-15
    导入包 声明包 包初始化 go语言
  • 如何在 Go 中创建一个共享内存的 Goroutine?
    可以通过 channel 实现共享内存的 goroutine:创建一个 channel 以指定元素类型。启动一个 goroutine 向 channel 写入数据。在主 goroutin...
    99+
    2024-05-16
    共享内存
  • 如何使用 Go 创建一个高效的 HTTP API?
    Go 是一种高效的编程语言,它的高并发性能和简单易学的语法使其成为构建 HTTP API 的首选语言之一。在这篇文章中,我们将介绍如何使用 Go 创建一个高效的 HTTP API,并给出一些示例代码。 创建一个简单的 HTTP API ...
    99+
    2023-07-23
    http api leetcode
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作