4

我有看起来像这样的代码

mTestModeMetadataTimer = new System.Threading.Timer(SomeTimerCallback, null, 1000, Timeout.Infinite);

Stopwatch tmStopwatch = new Stopwatch();

private void SomeTimerCallback(object state)
{
    // doing minimal work here

    Console.WriteLine("{0}: SomeTimerCallback time: {1}", System.Threading.Thread.CurrentThread.ManagedThreadId, tmStopwatch.ElapsedMilliseconds);
    tmStopwatch.Restart();

    // Better to be on the safe side and do this slightly more than once per second, than slightly less.
    mTestModeMetadataTimer.Change(990, Timeout.Infinite);
}

一切正常,只是偶尔会在此控制台输出中看到计时器事件之间存在巨大延迟。

 31: SomeTimerCallback time: 998
 21: SomeTimerCallback time: 997
 20: SomeTimerCallback time: 999
 3: SomeTimerCallback time: 989
 3: SomeTimerCallback time: 1000
 3: SomeTimerCallback time: 994
 37: SomeTimerCallback time: 999
 3: SomeTimerCallback time: 991
 29: SomeTimerCallback time: 1002
 37: SomeTimerCallback time: 1000
 3: SomeTimerCallback time: 17568
 3: SomeTimerCallback time: 999
 29: SomeTimerCallback time: 993

这是一个相当大的应用程序的一小部分。System.Timers.Timer 存在相同的行为,事实上,在整个应用程序中的其他不同时间都会发生。我将线程 ID 添加到这个特定计时器的控制台输出中,希望能更深入地了解为什么在正确的一秒事件中随机经过 17.5 秒的时间。

有什么我明显做错了吗?也许我可以收集更多数据来弄清楚为什么我的计时器表现得很有趣?

这里的任何建议将不胜感激。

4

3 回答 3

2

从您的评论来看,发生这种情况的原因是您正在耗尽线程池中的线程。因为每个线程都在使用中,所以计时器必须等待 17.5 秒才能使线程可用,然后才能运行。

正如我所看到的,您的选择是增加线程池中的最大线程数,或者使用不使用线程池的不同计时器(使用不使用线程池System.Timers.Timer同步对象(仍然使用线程池来踢它关闭)或System.Windows.Forms.Timer消息泵正在运行)

于 2014-05-28T14:20:37.060 回答
2

System.Threading.Timer在从 CLR 线程池获得的工作线程上调用事件处理程序。如果线程池处于饥饿状态,则回调可能会排队等待线程被释放。

要检查是否耗尽了线程池,可以在调试时定期记录可用线程的数量:

int workerThreads;
int completitionPortThreads;
System.Threading.ThreadPool.GetAvailableThreads(out workerThreads, out completitionPortThreads);
于 2014-05-28T14:20:46.360 回答
0

尝试使用 Timer 构造函数中的周期性:

mTestModeMetadataTimer = new System.Threading.Timer(SomeTimerCallback, null, 1000, TimeSpan.FromMilliseconds(990));

您确定您没有处于调试模式并且您在继续之前让时间过去了吗?

于 2014-05-28T14:04:39.273 回答