我是靠谱客的博主 淡定口红,最近开发中收集的这篇文章主要介绍C#计时,使用Stopwatch加List进位,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

当Stopwatch的属性ElapsedMilliseconds(单位:ms毫秒)一直增加时,会溢出,虽然过程很长,但是只要程序不中断肯定会溢出。

为了解决这个问题,利用集合进位的思想存。

首先看看这个类所有的成员

 

是不是很简单?实际代码就180多行,太简单了。

里面注释的很详细就不啰嗦介绍了,直接上代码 

public class TimerCenterCarry
    {
        /// <summary>
        /// 实例同步锁
        /// </summary>
        static readonly object instanceSynObj = new object();
        /// <summary>
        /// 唯一实例
        /// </summary>
        static TimerCenterCarry instance;
        /// <summary>
        /// 服务端唯一实例
        /// </summary>
        public static TimerCenterCarry Instance
        {
            get
            {
                if (instance == null)
                {
                    lock (instanceSynObj)
                    {
                        if (instance == null)
                        {
                            instance = new TimerCenterCarry();
                        }
                    }
                }
                return instance;
            }
        }
        List<long> TimerCarry;
        private Stopwatch sw;
        /// <summary>
        /// 定义长度
        /// </summary>
        long _longMaxValueHalf = 0L;
        /// <summary>
        /// 判断程序是否启动
        /// </summary>
        bool _isStart = false;
        /// <summary>
        /// 进位记录第一位值
        /// </summary>
        long first = 0L;
        /// <summary>
        /// 私有构造函数
        /// </summary>
        private TimerCenterCarry()
        {
            sw = new Stopwatch();
            TimerCarry = new List<long>();
        }
        /// <summary>
        /// 后台任务定时器,定期检测Stopwatch,防止Stopwatch溢出
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void TimerElapsed(object sender, ElapsedEventArgs e)
        {
            // 加锁,防止检查线程与调用线程冲突
            lock (this)
            {
                CalculationTime(sw.ElapsedMilliseconds);
            }
        }
        /// <summary>
        /// 逻辑函数
        /// </summary>
        /// <param name="curTime"></param>
        private void CalculationTime(long curTime)
        {
            curTime += first;
            RecursionTime(curTime);
            if (curTime > _longMaxValueHalf)
            {
                sw.Restart();
            }
        }
       
        /// <summary>
        /// 递归自动进位
        /// </summary>
        /// <param name="curValue"></param>
        /// <param name="startIndex"></param>
        private void RecursionTime(long curValue, int startIndex = 1)
        {
            // 添加容器
            if (TimerCarry.Count==0 
                || (TimerCarry.Count == 1 && curValue > _longMaxValueHalf) 
                || (TimerCarry.Count > 1 && (TimerCarry.Last() + 1) > _longMaxValueHalf))
            {
                // 防止一开始值很大
                if (TimerCarry.Count == 0 && curValue > _longMaxValueHalf)
                {
                    var num = GetContainerNum(curValue);
                    while (num-- > 0)
                    {
                        TimerCarry.Add(0);
                    }
                }
                TimerCarry.Add(0);
            }

            // 值未超过定义的值
            if (curValue <= _longMaxValueHalf)
            {
                TimerCarry[startIndex - 1] = curValue;

                return;
            }
           
            // 值超过定义的值,做进位
            TimerCarry[startIndex] = TimerCarry[startIndex] + 1;
            // 防止超出
            RecursionTime(TimerCarry[startIndex], startIndex + 1);

            TimerCarry[startIndex - 1] = curValue - _longMaxValueHalf;
            // 防止超出
            RecursionTime(TimerCarry[startIndex - 1], startIndex);
            // 进位后需要把第一位的数字记录
            first = TimerCarry.First();
        }
        private long GetContainerNum(long curValue)
        {
            long value = curValue / _longMaxValueHalf;
            if (value < _longMaxValueHalf)
                return 1;
            else if (value == _longMaxValueHalf)
                return 2;
            else
                return 2 + GetContainerNum(value) ;
        }
        /// <summary>
        /// 启动程序
        /// </summary>
        /// <param name="interval">默认半个月检查一次1296000000</param>
        /// <param name="longMaxValueHalf">默认long.MaxValue的一半</param>
        /// <exception cref="Exception"></exception>
        public void Start(double interval= 1296000000, long longMaxValueHalf= long.MaxValue>>1)
        {
            if (longMaxValueHalf > long.MaxValue >> 1)
                throw new Exception("longMaxValueHalf值不能比long.MaxValue的一半还大");

            _longMaxValueHalf=longMaxValueHalf;
            _isStart=true;
            sw.Start();
            
            Timer myTimer = new Timer(interval);
            myTimer.Elapsed += new System.Timers.ElapsedEventHandler(TimerElapsed);
            myTimer.AutoReset = true;
            myTimer.Enabled = true;
            myTimer.Start();
        }
        /// <summary>
        /// 获取自定义长度
        /// </summary>
        public long GetLongMaxValueHalf => this._longMaxValueHalf;
        /// <summary>
        /// 判断Stopwatch timer是否在运行
        /// </summary>
        public bool StopwatchIsRunning => sw.IsRunning;

        public void StopwatchRestart()
        {
            sw.Restart();
        }
        public void StopwatchStop()
        {
            sw.Stop();
        }
        public void StopwatchStart()
        {
            sw.Start();
        }
        /// <summary>
        /// 获取当前时间
        /// </summary>
        public List<long> GetTimesNow
        {
            get
            {
                if (!_isStart)
                    throw new Exception("程序未启动,请先启动!");
                // 加锁,防止检查线程与调用线程冲突,因为List线程不安全
                lock (this)
                {
                    CalculationTime(sw.ElapsedMilliseconds);
                }
                return TimerCarry;
            }
        }
    }

最后

以上就是淡定口红为你收集整理的C#计时,使用Stopwatch加List进位的全部内容,希望文章能够帮你解决C#计时,使用Stopwatch加List进位所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(39)

评论列表共有 0 条评论

立即
投稿
返回
顶部