2017-03-28 63 views
1

我試圖找出實現延遲到Task的最佳方式,以便延遲後它再次調用自己以嘗試相同的工作。使用Task.Delay和遞歸調用

我的應用程序是在移動設備與服務器同步數據後從數據庫生成報告的服務器,但是如果另一個用戶最近調用了報告生成方法,我希望它暫停一段時間,然後試圖再次運行。

這是我目前的嘗試

private static DateTime _lastRequest = Datetime.MinValue; 


public async void IssueReports() 
{ 
    await Task.Run(() => 
    { 
     if (DateTime.Now < _lastRequest + TimeSpan.FromMinutes(3)) //checks to see when a user last completed this method 
     { 
      Task.Delay(TimeSpan.FromMinutes(2)); 
      IssueReports(); //calls itself again after the delay 
      return; 
     } 
    }); 

    //code to generate reports goes here 
    _lastRequest = DateTime.Now; //updates last request into the static variable after it has finished running 

} 

開始,如果它沒有通過檢查,則任務會剛剛結束。這阻止了2個用戶同時訪問數據庫,並導致生成重複的報告。但是,問題是,如果2個用戶在同一個窗口內同步,則第二個用戶報告將不會被髮送,直到另一個同步呼叫完成。

延遲是應該給服務器時間來完成生成報告和更新數據庫之前通過調用自己請求下一批。

我是不是過於複雜?我很擔心,如果報告需要很長時間才能處理多個循環,系統資源可能會受到影響

+1

你最好使用計時器在x分鐘後運行任務。 'Task.Delay(TimeSpan.FromMinutes(2));'會阻止你的場景中不是好東西的線程。 –

+0

@ i.net該方法本身是從客戶端異步調用,所以它不會導致直接的問題 - 我不認爲。在這一點上阻塞線程會產生什麼問題? – Takarii

+1

我完全不明白這段代碼應該做什麼(即使有你的解釋),但要注意你的'Task.Delay(TimeSpan.FromMinutes(2)); '電話實際上什麼都不做,因爲你不等它完成。 – Evk

回答

0

下面的示例每10秒遞歸運行一次後臺服務。僅當您相信您的任務將在10秒內完成時,才推薦使用此方法。

public frm_testform() 
{ 

    InitializeComponent(); 

    dispatcherTimer_Tick().DoNotAwait(); 

} 

private async Task dispatcherTimer_Tick() 
{ 
    DispatcherTimer timer = new DispatcherTimer(); 
    TaskCompletionSource<bool> tcs = null; 
    EventHandler tickHandler = (s, e) => tcs.TrySetResult(true); 

    timer.Interval = TimeSpan.FromSeconds(10); 
    timer.Tick += tickHandler; 
    timer.Start(); 

    while (true) 
    { 
     tcs = new TaskCompletionSource<bool>(); 

     await Task.Run(() => 
     { 
     // Run your background service and UI update here 
     await tcs.Task; 
    } 

} 
+0

這個任務很可能需要10秒以上才能完成,那麼將間隔增加到5分鐘的時間會產生很大的影響嗎?我知道定時器可能會變得不一致,他們運行的時間越長 – Takarii

+0

不!它不會有很大的影響。您可以根據需要設定時間。以上代碼將每x分鐘/秒重複運行一次。 –

+0

多個定時器可能會導致線程池已滿並且會將其排隊。如果您使用較少的定時器,則在應用程序中使用定時器沒有問題。 –