.NET 7:如何让Timer回调在自定义TaskScheduler中执行?
问题解答
不行,没办法让System.Threading.Timer的Tick回调直接在你创建的ConcurrentExclusiveSchedulerPair独占调度器上执行。
原因
System.Threading.Timer的回调是由CLR线程池中的线程直接触发执行的,它的调度逻辑和TaskScheduler体系完全独立,.NET没有提供任何API可以指定Timer回调要绑定到某个特定的TaskScheduler运行。
你的现有方案是标准做法,可优化写法
你当前在Timer回调中通过TaskFactory将任务提交到目标调度器的方式,本身就是处理这类场景的常规手段。如果想让代码更简洁,也可以直接用Task.Factory.StartNew指定调度器(提前创建TaskFactory的写法也完全没问题,看个人习惯):
static void Tick(object? state) { var self = state as MyTimerScheduler; Task.Factory.StartNew(() => { // 模拟计算 Thread.Sleep(10_000); }, CancellationToken.None, TaskCreationOptions.None, self.schedulerPair.ExclusiveScheduler); }
另外,因为你用的是独占调度器(ExclusiveScheduler),它本身保证同一时间只会执行一个任务,所以不用担心Timer周期性触发导致的任务重叠问题——即便Timer回调被多次触发,后续的任务也会排队等待前一个任务执行完毕后再运行。
如果你的场景需要严格控制Timer的触发时机(比如必须等上一次计算完成后再等待指定间隔才触发下一次),可以在回调开始时先暂停Timer,待调度器中的任务执行完成后再恢复,避免不必要的回调触发:
static void Tick(object? state) { var self = state as MyTimerScheduler; // 暂停Timer,避免后续触发 self.timer.Change(Timeout.Infinite, Timeout.Infinite); self.simulationFactoryTask.StartNew(() => { try { // 模拟计算 Thread.Sleep(10_000); } finally { // 恢复Timer周期触发 self.timer.Change(self.deltaTime, self.deltaTime); } }); }
内容的提问来源于stack exchange,提问作者EduBic
相关产品推荐
相关产品推荐

