2017-06-02 67 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); 
    } 
}