Windows Service中如何按固定间隔(含任务耗时)执行异步任务
解决方案
1. 实现固定间隔执行(包含任务耗时)
要让任务从启动到下一次启动的间隔固定为n秒(包含任务自身耗时),核心是计算任务执行后需要补充的延迟时间,而非固定延迟5秒。
修改后的循环代码如下:
var interval = TimeSpan.FromSeconds(5); // 定义固定间隔为5秒 CancellationToken stoppingToken = new(); while (!stoppingToken.IsCancellationRequested) { var loopStartTime = DateTime.UtcNow; // 记录循环起始时间(用UTC时间规避时区/夏令时问题) // 串行执行异步任务,确保同一时间只有一个任务在运行 await DoJob(); // 计算任务耗时,得出需要补充的延迟时长 var elapsedTime = DateTime.UtcNow - loopStartTime; var delayTime = interval - elapsedTime; // 若任务耗时未超过间隔,补充剩余时间的延迟;若耗时已超,直接进入下一轮 if (delayTime > TimeSpan.Zero) { await Task.Delay(delayTime, stoppingToken); } }
同时,将DoJob中的阻塞式Thread.Sleep替换为异步非阻塞的Task.Delay,避免浪费线程资源:
private async Task DoJob() { await Task.Delay(3000); // 替代Thread.Sleep(3000),符合异步编程规范 }
修改后日志会呈现固定5秒间隔的效果:
Loop started at 07.06.2024 12:01:46 Start Job at 07.06.2024 12:01:46 Ended Job at 07.06.2024 12:01:49 Loop started at 07.06.2024 12:01:51 // 延迟2秒后启动下一轮,间隔正好5秒 Start Job at 07.06.2024 12:01:51 Ended Job at 07.06.2024 12:01:54 Loop started at 07.06.2024 12:01:56 Start Job at 07.06.2024 12:01:56 Ended Job at 07.06.2024 12:01:59
2. 避免任务耗时超间隔时重复启动
上述代码通过串行执行任务(await DoJob())天然避免了重复启动:只有当前任务完全执行完毕后,才会进入下一轮循环,永远不会同时运行多个DoJob实例。
如果任务耗时超过5秒(比如DoJob耗时6秒),代码会在任务结束后直接进入下一轮循环,不会额外延迟,确保不会出现任务重叠的情况。
内容的提问来源于stack exchange,提问作者Helmut
相关产品推荐
相关产品推荐

