c# - System.Threading.Timer 无法正常工作
问题描述
我注意到计时器不正确。
这是一个非常简单的 C# 代码:它将每 1 分钟打印一次当前日期/时间。我的预期结果是:让它在下午 3:30 运行,然后我们将有:下午 3:31、下午 3:32、下午 3:33,...
但有时不会收到上述结果:有时是下午 3:31、下午 3:32、下午 3:34,...
所以它失去了1行。
谁能指出我有什么问题?
class Program
{
static Timer m_Timer;
static int countDown;
static void Main(string[] args)
{
countDown = 60;
m_Timer = new Timer(TimerCallback, null, 0, 1000);
while (true) { System.Threading.Thread.Sleep(10); };
}
static void TimerCallback(Object o)
{
countDown -= 1;
if (countDown <= 0)
{
Console.WriteLine(" ===>>>>>" + System.DateTime.Now.ToString());
countDown = 60;
}
System.Threading.Thread.Sleep(10000); //long running code demo
}
}
解决方案
System.Threading.Timer 在线程池中的线程上运行。您运行回调函数,该函数每 1 秒在池中的一个线程上运行,并使用睡眠将其阻塞 10 秒。根据您在某些时间点线程池中有多少线程,它们都可能被阻塞并等待,或者.NET 应该为您分配池中最大线程数的新线程。
从评论扩展答案。
每个功能都是独立的,它不会等到另一个处理完成。一个简单的任务是:每隔 1 分钟调用一个函数来做某事。就我而言,“做某事”是将局部变量保存到 SQL Server 中。这个过程快不慢。我将 1 个计时器用于许多功能,因为每个功能都在不同的周期中安排。例如,功能 1 每 1 分钟触发一次,功能 2 每 10 秒触发一次……这就是我使用 1 秒计时器的原因。
当我从最初的问题中阅读时,您的用例似乎更复杂。您有不同的任务并尝试实现某种调度程序。也许每个特定的任务都很快,但总而言之,一些运行可能会更长且阻塞。不确定这个逻辑是如何很好地实现的,但可能会有很多边缘情况,例如错过了一些运行等。
我将如何处理它?
- 如果调度程序可以更复杂,我不会尝试自己实现。我会选择现成的解决方案,例如Quartz.NET。他们考虑边缘情况并帮助在需要的情况下扩展集群并帮助配置。
- 在任何情况下,我都会重构更大的计划,让每个任务根据配置(自定义实现或 Quartz)作为更小的任务按其计划运行
- 我将首先通过引入一些队列在本地扩展您的任务“队列”,例如使用 ConcurrentQueue 或BlockingCollection或任何生产消费者来限制线程数,并且如果此类执行的性能在集群上的扩展性不好。通过这样做,您至少可以保证 N 个任务可以在本地调度和执行,并且超出的所有任务都可以排队。也许为任务设置一些优先级也会有所帮助,因为可能会错过一些执行,但有些执行必须按计划运行。
如果您很可能已经遇到线程问题,我怀疑从线程计时器执行其他线程或任务开始是一个好主意。
你的问题不在于 System.Threading.Timer,它的工作做得很好。您的用例更复杂。
推荐阅读
- python - Google Api + 使用 python 列出组的成员
- asp.net - LinqDataSource WHERE 查询 - ASP.NET
- android - 从服务器获取 JSON 列表后如何正确更新数据集?
- javascript - 异步流控制,不抛出错误
- php - Using POST to update values through HTML form retrieves old values
- c++ - Qt:如何将不同类的静态信号连接到插槽?
- scheme - 这是一个可用的方案功能吗?
- javascript - 置换函数变量范围错误,不会在函数范围之外更新我的结果 arr
- swift - 如何处理带有节点顺序很重要的可选节点的 XML 文档
- typescript - React + typescript + Redux 连接功能不起作用