C# 高精度定时器

一:常规版

  方法A实现了AAAAA...循环执行,且做到A和A之间的时间间隔相同

using System.Diagnostics;
using System.Runtime.InteropServices;

namespace App10
{

    internal class Program
    {
        private static void MethodA()
        {
            // 替换为你的实际方法逻辑
            Console.WriteLine($"Method A executed at {DateTime.UtcNow:HH:mm:ss.fffffff}");
        }

        static void Main(string[] args)
        {
            var timer = new HighPrecisionTimer(MethodA);
            timer.Start();

            // 运行一段时间后停止
            Thread.Sleep(5000); // 运行 5 秒
            timer.Stop();

            // 等待用户输入以防止程序退出
            Console.WriteLine("Press any key to exit...");
            Console.ReadKey();
        }
    }
    public class HighPrecisionTimer
    {
        // P/Invoke 声明
        [DllImport("winmm.dll", EntryPoint = "timeBeginPeriod", SetLastError = true)]
        private static extern uint TimeBeginPeriod(uint uMilliseconds);

        [DllImport("winmm.dll", EntryPoint = "timeEndPeriod", SetLastError = true)]
        private static extern uint TimeEndPeriod(uint uMilliseconds);

        private readonly Action _methodToExecute;
        private readonly double _intervalMs = 0.5; // 目标间隔 0.5ms
        private volatile bool _isRunning;
        private readonly uint _timerResolution = 1; // 设置定时器分辨率为 1ms

        public HighPrecisionTimer(Action method)
        {
            _methodToExecute = method ?? throw new ArgumentNullException(nameof(method));
        }
        public void Start()
        {
            if (_isRunning)
                return;

            _isRunning = true;

            // 设置高精度定时器分辨率
            uint result = TimeBeginPeriod(_timerResolution);
            if (result != 0)
            {
                Console.WriteLine($"Failed to set timer resolution: {result}");
                return;
            }

            // 在单独线程中运行高精度循环
            ThreadPool.QueueUserWorkItem(_ =>
            {
                var stopwatch = Stopwatch.StartNew();
                long nextTick = stopwatch.ElapsedTicks;

                while (_isRunning)
                {
                    // 计算下一次执行的时间点(以 ticks 为单位)
                    nextTick += (long)(Stopwatch.Frequency * _intervalMs / 1000.0);

                    // 执行方法
                    try
                    {
                        _methodToExecute();
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine($"Error executing method: {ex.Message}");
                    }

                    // 自旋等待直到达到目标时间
                    while (stopwatch.ElapsedTicks < nextTick)
                    {
                        Thread.SpinWait(10); // 短暂自旋,避免过度占用 CPU
                    }

                    // 如果落后太多,重置时间基准以避免累积误差
                    if (stopwatch.ElapsedTicks > nextTick + (long)(Stopwatch.Frequency * _intervalMs / 1000.0))
                    {
                        nextTick = stopwatch.ElapsedTicks;
                    }
                }

                // 清理定时器分辨率
                TimeEndPeriod(_timerResolution);
                stopwatch.Stop();
            });
        }
        public void Stop()
        {
            _isRunning = false;
        }
    }
}

 

 

二:进阶版

  方法A、方法B实现了ABABABA...循环执行,且做到A和B之间时间间隔相同

using System.IO;
using System.Collections.Concurrent;

namespace DataSync.DataCore
{
    public class DataProcessor<T>
    {
        private readonly ConcurrentBag<T> _dataCollection = new ConcurrentBag<T>();
        private readonly string _outputDirectory;
        private readonly TimeSpan _interval = TimeSpan.FromMinutes(2);
        private CancellationTokenSource _cts = new CancellationTokenSource();
        private DateTime _currentPeriodStart;

        public DataProcessor(string outputDirectory)
        {
            _outputDirectory = outputDirectory ?? throw new ArgumentNullException(nameof(outputDirectory));
            Directory.CreateDirectory(_outputDirectory);
            _currentPeriodStart = AlignToInterval(DateTime.UtcNow);
        }

        // 添加数据到集合
        public void AddData(T data)
        {
            _dataCollection.Add(data);
        }

        // 启动处理
        public Task StartAsync()
        {
            return Task.Run(async () =>
            {
                while (!_cts.Token.IsCancellationRequested)
                {
                    DateTime now = DateTime.UtcNow;
                    DateTime nextPeriod = _currentPeriodStart.Add(_interval);

                    if (now >= nextPeriod)
                    {
                        await ProcessDataAsync();
                        _currentPeriodStart = AlignToInterval(now);
                    }

                    TimeSpan delay = nextPeriod - now;
                    if (delay > TimeSpan.Zero)
                    {
                        await Task.Delay(delay, _cts.Token);
                    }
                }
            }, _cts.Token);
        }

        // 停止处理
        public void Stop()
        {
            _cts.Cancel();
            _cts.Dispose();
            _cts = new CancellationTokenSource();
        }

        // 处理数据并生成文件
        private async Task ProcessDataAsync()
        {
            if (_dataCollection.IsEmpty)
                return;

            var dataToProcess = new ConcurrentBag<T>();
            while (_dataCollection.TryTake(out var item))
            {
                dataToProcess.Add(item);
            }

            if (dataToProcess.IsEmpty)
                return;

            string fileName = Path.Combine(_outputDirectory,
                $"{_currentPeriodStart:yyyyMMdd_HHmmss}.txt");

            try
            {
                using (var writer = new StreamWriter(fileName, false))
                {
                    foreach (var item in dataToProcess)
                    {
                        await writer.WriteLineAsync(item?.ToString());
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error writing to file {fileName}: {ex.Message}");
            }
        }

        // 对齐到2分钟间隔
        private DateTime AlignToInterval(DateTime dt)
        {
            long ticks = dt.Ticks / _interval.Ticks;
            return new DateTime(ticks * _interval.Ticks, dt.Kind);
        }
    }
}

 

posted @ 2025-06-09 15:33  超级驼鹿  阅读(198)  评论(0)    收藏  举报
/*