Windows服务中System.Threading.Timer定时偏差5秒,如何保证同秒执行?
解决Windows服务定时任务每小时偏差问题
问题根源
你用的System.Threading.Timer默认是相对周期调度:以上一次任务执行完成的时间为起点,加上设置的3600秒作为下一次执行时间。如果任务本身有耗时、系统调度有延迟,偏差会不断累计,就出现了每次晚5秒的情况。
解决方案:改用绝对时间调度
不要固定周期,每次计算下一个目标时间点(比如每小时的同一分秒),动态设置Timer的下一次执行延迟。
步骤1:写一个计算下一次执行时间的方法
private DateTime GetNextTargetTime() { var now = DateTime.Now; // 目标是每小时的0分0秒执行,可根据需求调整分秒 var nextTarget = new DateTime(now.Year, now.Month, now.Day, now.Hour + 1, 0, 0); // 如果当前时间已经过了本次整点(比如10:00:05),直接取下一个小时的整点 if (now >= nextTarget) { nextTarget = nextTarget.AddHours(1); } return nextTarget; }
步骤2:初始化Timer
首次执行时,计算当前时间到下一个目标点的延迟:
var firstDelay = GetNextTargetTime() - DateTime.Now; // 初始延迟用计算出的时间,周期设为无限(后续手动更新) _timer = new Timer(DestFunction, null, firstDelay, Timeout.InfiniteTimeSpan);
步骤3:任务执行完后更新Timer
在你的任务方法DestFunction末尾,重新计算下一次延迟并更新Timer:
private void DestFunction(object state) { // 执行你的核心任务逻辑 // ... // 计算下一次执行的延迟 var nextDelay = GetNextTargetTime() - DateTime.Now; // 更新Timer的下一次执行时间 _timer.Change(nextDelay, Timeout.InfiniteTimeSpan); }
额外注意事项
- 如果需要不受系统本地时间调整影响,可以改用
DateTime.UtcNow计算,再转换为本地时间(根据你的业务需求选择)。 - 任务执行时间要控制在目标间隔内,比如别让任务执行超过1小时,否则会跳过下一次调度。
内容的提问来源于stack exchange,提问作者FelipeFonsecabh
相关产品推荐
相关产品推荐

