2017-06-02 62 views
0

对于工作中的一个侧面项目,我试图让一段代码在特定时间每24小时运行一次。我的老板让我用一个无限循环代替C#的timer类,这是我正在处理的主要约束。我的问题是,代码将在第一个24小时内运行(即它将在​​我设置的那一天运行代码),但之后它不会更新。我没有被抛出任何异常或错误,所以我认为这只是我的逻辑问题。设置代码以每24小时运行

这是我现在的代码的要点。

int i = 0; 
while (true) 
{ 
    DateTime currentdate = DateTime.Now; 
    String time = currentdate.ToString("HH:mm"); 

    if ((time == "23:50" || time == "23:51") && i == 0) 
    { 
     HistoricalAverageCollection HAC = new HistoricalAverageCollection(); 
     HAC.ExecHAC(); 

     HistoricalAverageError HAE = new HistoricalAverageError(); 
     HAE.ExecHAE(); 
     FourWeekAverageCollection FWAC = new FourWeekAverageCollection(); 
     FWAC.ExecFWAC(); 
     FourWeekAverageError FWAE = new FourWeekAverageError(); 
     FWAE.ExecFWAE(); 

     DomainsReturningZeroTwentyFourHours DRZ = 
      new DomainsReturningZeroTwentyFourHours(); 
     DRZ.ExecDomainsReturningZero(); 

     context.SaveChanges(); 

     //Program should update every 24 horus 
     i = 1; 

     Console.Write("Updated The Historical Averages In The Data Base at..."); 
     Console.Write(DateTime.Now); 
     Console.WriteLine("i is -> {0}", i); 
     Console.Read(); 
    } 
    else if (time == "06:00" && i == 1) 
    { 
     ReportEmail Report = new ReportEmail(); 
     Report.CreateAndSendReport(); 
     i = 0; 
     Console.Write("counter reset. I is now -> {0} /n Email Sent",i); 
     Console.Read(); 
    } 
} 

代码设置晚上11:50打电话给一堆TSQL存储过程,然后在早上6点发送基于该数据的电子邮件报告。但是,它只会运行一次,我发现自己在一两天后的早晨醒来,看到没有电子邮件正在发送。

任何帮助,将不胜感激:)

+12

你不使用计划任务此的原因吗? – jAC

+5

是否有你的老板不想使用Windows任务计划程序的原因?这是它所做的确切的事情。 – Amy

+0

是否可以使用Windows任务调度程序每24小时运行一次exe? Windows任务计划程序有很多自定义选项,可以让它每x次运行一次并重复该过程。 – WBuck

回答

0

保持一个时间变量,表示“下一步”日期时间运行。

在你的循环中,检查当前的时间,然后运行你的代码..然后重置变量到下一个白天,即现在+24小时。

为另一种答案表示问题出在线路:

Console.Read(); 

需要被去除

9

我会第二的许多意见建议这样做的其他更适合的方法,但我相信你的问题是:

Console.Read(); 

从文档:

Read方法在键入输入字符时阻止其返回;当您按下Enter键时,它会终止。

因此,它会阻止等待一个永远不会来的条目。

+1

我宁愿使用Windows任务计划程序,但无论出于何种原因,这并不理想。该程序并没有真正使用大量的资源,所以我认为这不是什么大问题。 –

+0

好吧,但既然你只检查分钟,你可以在你的代码中加入一个'Thread.Sleep(60000);',这样它就不会不必要地运行。这会使线程执行停止一分钟(60(秒)* 1000(毫秒))。 – jAC

+0

是的,我补充说,感谢帮助。仍然非常新手在C#。 –

0

如果你真的想用手工完成这一切,而不使用定时器或现有的调度程序设施,我建议你更严格一点,并自己构建一个简单的任务调度程序类。该部分你需要:

  • 类存储每个任务,其中包括代码为任务和各个任务应该运行计划执行。
  • 这样的任务
  • 计算下一个截止日期是从你的任务列表,让你知道多长时间睡眠的方法的列表。
  • 一个SemaphoreSlim上(而不是Thread.Sleep())睡眠
    • 使用SemaphoreSlim因为它作为一个Thread.Sleep()通过传递它,如果信号永远不会释放的等待时间;而且还因为如果您的调度程序确定添加了新任务并且应该醒来重新评估下一个截止日期,您可以手动将其释放。

我建议你存储UTC的最后期限,并使用UTC时间做大部分的时间计算的工作,这种方式有没有约时区变化或DST混乱。

你也应该考虑不只是在整个时间内睡觉,直到下一个最后期限,以防万一NTP更新到PC的系统时间。考虑一次最多睡1个小时。

一些亮点,让你开始:

public void Run() 
{ 
    this.running = true; 

    do 
    { 
     DateTime nextDeadlineUtc; 
     ScheduledTask nextTask; 
     bool deadlineExpired; 

     nextDeadlineUtc = ComputeNextDeadline(out nextTask); 

     deadlineExpired = WaitForDeadline(nextDeadlineUtc); 

     if(deadlineExpired) 
     { 
      // We hit the deadline. Execute the task and move on. 
      nextTask.Execute(); 
     } 
     else 
     { 
      // We were woken up before the deadline expired. That means either we're shutting 
      // down, or we need to recompute our next deadline because the schedule changed. 
      // To deal with this, just do nothing. We'll loop back around and either find out 
      // we're being asked to stop, or we'll recompute the next deadline. 
     } 
    } 
    while(this.running); 
} 

/// <summary> 
/// Sleeps until the deadline has expired. 
/// </summary> 
/// <param name="nextDeadlineUtc">The next deadline, in UTC</param> 
/// <returns> 
/// True if the deadline has elapsed; false if the scheduler should re-examine its next deadline. 
/// </returns> 
private bool WaitForDeadline(DateTime nextDeadlineUtc) 
{ 
    TimeSpan wait; 
    bool incompleteDeadline; 
    bool acquired; 

    wait = ComputeSleepTime(nextDeadlineUtc, out incompleteDeadline); 

    acquired = this.waiter.Wait(wait); 

    if(acquired || incompleteDeadline) 
    { 
     // Either: 
     // - We were manually woken up early by someone releasing the semaphore. 
     // - The timeout expired, but that's because we didn't wait for the complete time. 
     // 
     // Either way, the deadline didn't expire. 
     return false; 
    } 
    else 
    { 
     // The deadline occurred. 
     return true; 
    } 
} 

private TimeSpan ComputeSleepTime(DateTime nextDeadlineUtc, out bool incompleteDeadline) 
{ 
    TimeSpan totalRemaining = nextDeadlineUtc - DateTime.UtcNow; 

    if(totalRemaining.Ticks < 0) 
    { 
     // Were already out of time. 
     incompleteDeadline = false; 
     return TimeSpan.FromTicks(0); 
    } 
    else if(totalRemaining.TotalHours <= 1.01) 
    { 
     // Just sleep the whole of the remainder. 
     incompleteDeadline = false; 
     return totalRemaining; 
    } 
    else 
    { 
     // More than one hour to sleep. Sleep for at most one hour, but tell the sleeper that 
     // there's still more time left. 
     incompleteDeadline = true; 
     return TimeSpan.FromHours(1.0); 
    } 
}