如何在.NET中每小时(或每小时的特定时间间隔)引发事件?

我正在开发一个小型网络爬虫,它将在系统托盘中运行,并在一小时内每小时抓取一个网站。

让.NET每小时或某个其他时间间隔提升事件以执行某项任务的最佳方法是什么。 例如,我想根据时间每20分钟运行一次事件。 该活动将在以下时间举行:

00:20 00:40 01:00 01:20 01:40 

等等。 我能想到的最好的方法是在线程上创建一个循环,不断检查时间是否可以被给定的时间间隔整除,并在达到时间时引发回调事件。 我觉得必须有一个更好的方法。

我会使用一个Timer但我更喜欢一些遵循“时间表”的东西,这些时间表就是按照那些时间线运行的。

如果没有在Windows任务调度程序中设置我的应用程序,这可能吗?

更新:
我正在添加我的算法来计算计时器的时间间隔。 此方法采用“ minute ”参数,这是计时器触发勾号的时间。 例如,如果“ minute ”参数为20,则计时器将按上述时间表中的间隔进行计时。

 int CalculateTimerInterval(int minute) { if (minute <= 0) minute = 60; DateTime now = DateTime.Now; DateTime future = now.AddMinutes((minute - (now.Minute % minute))).AddSeconds(now.Second * -1).AddMilliseconds(now.Millisecond * -1); TimeSpan interval = future - now; return (int)interval.TotalMilliseconds; } 

此代码使用如下:

 static System.Windows.Forms.Timer t; const int CHECK_INTERVAL = 20; static void Main() { t = new System.Windows.Forms.Timer(); t.Interval = CalculateTimerInterval(CHECK_INTERVAL); t.Tick += new EventHandler(t_Tick); t.Start(); } static void t_Tick(object sender, EventArgs e) { t.Interval = CalculateTimerInterval(CHECK_INTERVAL); } 

System.Timers.Timer 。 如果你想在一天中的特定时间运行,你需要确定它到下一次的时间长度并将其设置为你的间隔。

这只是基本的想法。 根据您需要的精确程度,您可以做更多事情。

 int minutes = DateTime.Now.Minute; int adjust = 10 - (minutes % 10); timer.Interval = adjust * 60 * 1000; 

以下是使用线程计时和异步调用的轻量级系统的示例。

我知道有一些缺点,但我喜欢在开始长时间运行的过程(如调度后端服务)时使用它而不是计时器。 由于它在计时器线程中内联运行,因此您不必担心它会在原始调用完成之前再次启动。 这可以延长相当多,以使其使用日期时间数组作为触发时间或为其添加更多function。 我相信你们中的一些人知道一些更好的方法。

  public Form1() { InitializeComponent(); //some fake data, obviously you would have your own. DateTime someStart = DateTime.Now.AddMinutes(1); TimeSpan someInterval = TimeSpan.FromMinutes(2); //sample call StartTimer(someStart,someInterval,doSomething); } //just a fake function to call private bool doSomething() { DialogResult keepGoing = MessageBox.Show("Hey, I did something! Keep Going?","Something!",MessageBoxButtons.YesNo); return (keepGoing == DialogResult.Yes); } //The following is the actual guts.. and can be transplanted to an actual class. private delegate void voidFunc(P1 p1,P2 p2,P3 p3); public void StartTimer(DateTime startTime, TimeSpan interval, Func action) { voidFunc> Timer = TimedThread; Timer.BeginInvoke(startTime,interval,action,null,null); } private void TimedThread(DateTime startTime, TimeSpan interval, Func action) { bool keepRunning = true; DateTime NextExecute = startTime; while(keepRunning) { if (DateTime.Now > NextExecute) { keepRunning = action.Invoke(); NextExecute = NextExecute.Add(interval); } //could parameterize resolution. Thread.Sleep(1000); } } 

System.Windows.Forms.Timer(或System.Timers.Timer)

但是现在你说你不想使用Timers,你可以在另一个线程上运行一个轻量级的等待进程(检查时间,睡几秒钟,再次检查时间……)或者创建一个引发事件的组件(使用某些预定时间或间隔的轻量级等待过程

另一种策略是记录进程运行的最后时间,并确定自那时起是否已经过了所需的时间间隔。 在此策略中,如果经过的时间等于或大于所需的时间间隔,则会对事件进行编码。 通过这种方式,您可以处理如果由于某种原因计算机出现故障而可能错过长间隔(例如,每天一次)的情况。

例如:

  • lastRunDateTime = 5/2/2009 at 8pm
  • 我想每24小时运行一次我的流程
  • 在计时器事件上,检查自上次运行进程以来是否已经过了24小时或更多。
  • 如果是,请运行该过程,通过向其添加所需的间隔来更新lastRunDateTime(在这种情况下为24小时,但无论您需要它是什么)

显然,为了在系统关闭后恢复,你需要将lastRunDateTime存储在某个文件或数据库中,以便程序可以在恢复时从中断。

我的目标是每晚03:00左右进行一次导入。

这是我的方法,使用System.Timers.Timer:

 private Timer _timer; private Int32 _hours = 0; private Int32 _runAt = 3; protected override void OnStart(string[] args) { _hours = (24 - (DateTime.Now.Hour + 1)) + _runAt; _timer = new Timer(); _timer.Interval = _hours * 60 * 60 * 1000; _timer.Elapsed += new ElapsedEventHandler(Tick); _timer.Start(); } void Tick(object sender, ElapsedEventArgs e) { if (_hours != 24) { _hours = 24; _timer.Interval = _hours * 60 * 60 * 1000; } RunImport(); }