如何设置Timer实现异步任务循环执行并解决触发失效问题?
问题分析与解决方案
核心问题
你的代码里Main方法启动Timer后,立刻调用了timer.Stop()和timer.Dispose(),而且async Main没有任何阻塞逻辑,程序直接执行到末尾终止,导致Timer的Elapsed事件根本没机会触发。另外,原Timer的固定10秒间隔逻辑,会无视前一次任务是否执行完成就触发下一次,可能导致任务重叠,不符合你“所有任务执行完成后等待10秒再从头开始”的需求。
解决方案
推荐用异步循环实现需求,既满足“启动立即执行”“任务完成后等10秒再循环”,也不会占用过多内存(await Task.Delay会释放当前线程,不会持续占用CPU)。同时修复Main方法的退出逻辑,确保程序在用户输入前保持运行。
修改后的代码:
public class Program { private static OpenSeaApiClient openSeaApiClient; private static int counter = 1; static async Task Main() { string apiKey = "myApiKey"; openSeaApiClient = new OpenSeaApiClient(apiKey); Console.WriteLine("Press Enter to exit."); // 启动后台循环任务 var loopTask = RunTaskLoopAsync(); // 阻塞主线程,防止程序提前退出 await Console.In.ReadLineAsync(); } private static async Task RunTaskLoopAsync() { while (true) { Console.WriteLine($"Counter: {counter++}"); // 依次执行所有Collection任务 var KarafuruXhypebeastXatmos = new Collection(openSeaApiClient, "karafuru-x-hypebeast-x-atmos", "0x32F2a60942E7563CFC42766018641C6C6b10830E", OfferVariables.initialValueOfferKarafuruXhypebeastXatmos); await KarafuruXhypebeastXatmos.ExecuteAsync(); var BricktopiansByLawDegree = new Collection(openSeaApiClient, "bricktopians-by-law-degree", "0x9eEeAF684E228C2D5C89435e010acC02c41Dc86B", OfferVariables.initialValueOfferBricktopiansByLawDegree); await BricktopiansByLawDegree.ExecuteAsync(); // 更多实例... // 所有任务执行完成后,等待10秒进入下一轮 await Task.Delay(TimeSpan.FromSeconds(10)); } } }
关键说明
- 异步循环特性:
while(true)配合await不会造成内存泄漏或高CPU占用,每次await都会释放当前线程,系统可将线程分配给其他任务,直到延迟结束或任务完成。 - 立即执行逻辑:程序启动后
loopTask会立刻执行第一轮任务,无需等待Timer触发。 - 退出控制:
Main方法用await Console.In.ReadLineAsync()阻塞主线程,确保程序在用户按下Enter前持续运行,后台循环任务也会一直执行。 - 避免任务重叠:必须等所有任务执行完成后才开始10秒等待,完全避免了任务并行执行的问题,符合你的需求。
如果坚持要用Timer实现(不推荐,因为Timer固定间隔不匹配“任务完成后等待”的场景),可以改为每次任务完成后重启Timer,代码示例:
public class Program { private static OpenSeaApiClient openSeaApiClient; private static Timer timer; private static int counter = 1; static async Task Main() { string apiKey = "myApiKey"; openSeaApiClient = new OpenSeaApiClient(apiKey); // 初始化Timer,先不启动 timer = new Timer(async _ => await ExecuteTasksAndRestartTimer(), null, Timeout.Infinite, Timeout.Infinite); Console.WriteLine("Press Enter to exit."); // 立即执行第一轮任务 await ExecuteTasksAndRestartTimer(); // 等待用户输入 await Console.In.ReadLineAsync(); // 清理Timer timer.Change(Timeout.Infinite, Timeout.Infinite); timer.Dispose(); } private static async Task ExecuteTasksAndRestartTimer() { Console.WriteLine($"Counter: {counter++}"); var KarafuruXhypebeastXatmos = new Collection(openSeaApiClient, "karafuru-x-hypebeast-x-atmos", "0x32F2a60942E7563CFC42766018641C6C6b10830E", OfferVariables.initialValueOfferKarafuruXhypebeastXatmos); await KarafuruXhypebeastXatmos.ExecuteAsync(); var BricktopiansByLawDegree = new Collection(openSeaApiClient, "bricktopians-by-law-degree", "0x9eEeAF684E228C2D5C89435e010acC02c41Dc86B", OfferVariables.initialValueOfferBricktopiansByLawDegree); await BricktopiansByLawDegree.ExecuteAsync(); // 更多实例... // 所有任务完成后,设置10秒后再次触发Timer timer.Change(TimeSpan.FromSeconds(10).TotalMilliseconds, Timeout.Infinite); } }
这个Timer版本的逻辑是:立即执行任务,任务完成后设置Timer在10秒后触发一次,触发时再次执行任务,以此循环,同样能保证任务完成后再等待10秒,不会出现重叠。
内容的提问来源于stack exchange,提问作者paro
相关产品推荐
相关产品推荐

