.Net Core 项目手写可以变化时间和倍速的计时器

185 阅读3分钟

一共分为四部分

一、在管道配置文件中添加定时任务

.Net6.0版本项目,在此位置添加这一行代码 TimeUtils 这个参数为计时器类的名称 image.png

二、创建计时器辅助类,书写计时器相关代码

//此类里面已经写好了定时器相关代码,创建、删除、时间增长等等

using System.Text.RegularExpressions;
using System;
namespace ReadJson_.Net6._0.Utils
{
    /// <summary>
    /// 计时器类
    /// </summary>
    public class TimeUtils : BackgroundService
    {
        /// <summary>
        /// 时间委托
        /// </summary>
        /// <param name="obj">时间</param>
        /// <param name="key">定时器名称</param>
        /// <returns></returns>
        public delegate Task TimerEvent(double obj, string key);

        /// <summary>
        /// 存储所有时间信息
        /// </summary>
        public static Dictionary<string, List<TimerEvent>> timerEvents = new Dictionary<string, List<TimerEvent>>();
        /// <summary>
        /// 存储当前时间  正常的时间 年月日时分秒
        /// </summary>
        public static Dictionary<string,DateTime> dateTimeKey = new Dictionary<string, DateTime>();
        /// <summary>
        /// 存储当前时间  时间为毫秒数 1970年1月1日到设定的计时器显示时间的毫秒数
        /// </summary>
        public static Dictionary<string, double> dateTimePairs = new Dictionary<string, double>();
        /// <summary>
        /// 存储时间倍速
        /// </summary>
        public static Dictionary<string,List<double>> dateTimeMulitKey = new Dictionary<string, List<double>>();

        /// <summary>
        /// 定时器
        /// </summary>
        /// <param name="stoppingToken"></param>
        /// <returns></returns>
        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            while (! stoppingToken.IsCancellationRequested) 
            {
                try
                {
                    foreach (var item in dateTimeMulitKey.Keys)
                    {
                        // dateTimeMulitKey["dateTimeMulit"][1] 的值代表倍速   *1000  代表 这个倍速实际一秒钟走过的时间
                        double multiplier = dateTimeMulitKey[item][1] * 1000;
                        //当前时间  原来的时间 + 倍速 * 一秒钟走过的时间
                        double dateTime = dateTimeMulitKey[item][0] + multiplier;
                        if (dateTimePairs.ContainsKey(item))
                        {
                            dateTime = dateTimePairs[item] + multiplier;
                        }
                         //事件派发
                        await DispatchEvent(item, dateTime);
                    }

                    //需要执行的任务
                    await Task.Delay(1000, stoppingToken); //等待一秒
                }
                catch (Exception ex)
                {
                    Console.WriteLine("当前时间判断错误{0}:", ex.Message);
                }
            }
        }

        /// <summary>
        /// 事件派发
        /// </summary>
        /// <param name="key"></param>
        /// <param name="dateTime"></param>
        /// <returns></returns>
        private static async Task DispatchEvent(string key, double dateTime)
        {
            await Task.Run(() =>
            {
                if (!timerEvents.ContainsKey(key))
                {
                    return;
                }

                foreach (TimerEvent timerEvent in timerEvents[key])
                {
                    //发送当前时间
                    timerEvent(dateTime, key);
                }
            });
        }

        /// <summary>
        /// 注册消息事件
        /// </summary>
        /// <param name="key"></param>
        /// <param name="timerEvent"></param>
        public static void RegisterEvern(string key, TimerEvent timerEvent)
        {
            if (!timerEvents.ContainsKey(key))
            {
                timerEvents.Add(key,new List<TimerEvent>());
            }
            timerEvents[key].Add(timerEvent);
        }

        /// <summary>
        /// 移除消息事件
        /// </summary>
        /// <param name="key"></param>
        /// <param name="timerEvent"></param>
        public static void RemoveEvent (string key, TimerEvent timerEvent)
        {
            if (!timerEvents.ContainsKey(key) || !timerEvents[key].Contains(timerEvent))
            {
                return;
            }
            timerEvents[key].Remove(timerEvent);
        }
    }
}

三、创建定时器辅助类

//此方法中封装了 定时器的初始化创建,删除,以及可以在计时器时间内执行操作的方法等等

namespace ReadJson_.Net6._0.Utils
{
    /// <summary>
    /// 定时器实现类
    /// </summary>
    public class TimeTask
    {
        /// <summary>
        /// 定时器初始化
        /// </summary>
        /// <param name="key">计时器名称</param>
        /// <param name="mulit">倍速</param>
        /// <param name="dateTime">时间</param>
        public static void Init (string key, double mulit, DateTime dateTime)
        {
            //1970年1月1日 到现在的总毫秒数
            double time = (long)(dateTime.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds;
            List<double> times = new List<double>()
            {
                time, //时间
                mulit //倍速
            };
            if (TimeUtils.dateTimeMulitKey.ContainsKey(key))
            {
                TimeUtils.dateTimeMulitKey.Remove(key);
            }
            //重新给全局计时器赋值
            TimeUtils.dateTimeMulitKey.Add(key, times);
            //注册计时器事件
            TimeUtils.RegisterEvern(key, TimeHandler);
            if (TimeUtils.dateTimeKey.ContainsKey(key))
            {
                TimeUtils.dateTimeKey.Remove(key);
            }
            if (TimeUtils.dateTimePairs.ContainsKey(key))
            {
                TimeUtils.dateTimePairs.Remove(key);
            }
        }

        /// <summary>
        /// 移除计时器
        /// </summary>
        /// <param name="key"></param>
        public static void EndTimeEvent(string key) 
        {
            TimeUtils.dateTimeMulitKey.Remove(key);
            TimeUtils.RemoveEvent(key, TimeHandler);
        }



        /// <summary>
        /// TimeHandler协议
        /// </summary>
        /// <param name="obj">时间</param>
        /// <param name="key">计时器名称</param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        private static async Task TimeHandler(double obj, string key)
        {
            await Task.Run(() =>
            {
                CurrentTime(key, obj);
                //可以书写一些 需要计时器执行的方法
                //比如: test变量 每过1.5秒需要自动+1
                
                Console.WriteLine(TimeUtils.dateTimeKey[key]);
                //能成功打印时间,计时器制造成功
            });
        }

        /// <summary>
        /// 添加当前时间
        /// </summary>
        /// <param name="key"></param>
        /// <param name="obj"></param>
        /// <exception cref="NotImplementedException"></exception>
        private static void CurrentTime(string key, double obj)
        {
            DateTime time = new DateTime(1970,1,1,0,0,0,DateTimeKind.Utc).AddMilliseconds(obj).ToLocalTime();
            //时间走动
            if (TimeUtils.dateTimeKey.ContainsKey(key))
            {
                TimeUtils.dateTimeKey[key] = time;
            }
            else
            {
                TimeUtils.dateTimeKey.Add(key, time);
            }
            //时间走动
            if (TimeUtils.dateTimePairs.ContainsKey(key))
            {
                TimeUtils.dateTimePairs[key] = obj;
            }
            else
            {
                TimeUtils.dateTimePairs.Add(key, obj);
            }
        }
    }
}

到了此步骤,手写定时器差不多就完成了,接下来只需要调用即可

四、定时器调用

image.png 在接口中,按照自己的需求,根据途中文中操作即可