2015-07-13 41 views
4

我有一個Windows服務(.NET 4.5.2),它應該在後臺運行多個任務,同時我想使用System.Threading.Tasks以下哪種實現方式正在考慮最佳實踐?還是我完全錯了?運行多個後臺任務的最佳做法是什麼

方案1:

protected override void OnStart(string[] args) 
{ 
    // Assume all tasks implemented the same way. 
    // I believe we shouldn't await the tasks in this scenario. 
    var token = this._cancellationTokenSource.Token; 
    this.RunTask1(token); 
    this.RunTask2(token); 
    this.RunTask3(token); 
} 

private async Task RunTask1(CancellationToken token) 
{ 
    var telebot = new Telebot("SOMETHING"); 
    while(true) 
    { 
     // Some work... 
     // I/O dependent task. 
     var response = await telebot.GetUpdatesAsync(cancellationToken: token); 

     // 
     // Some other work 
     // maybe some database calls using EF async operators. 
     // 
     await Task.Delay(TimeSpan.FromSeconds(1), token); 
    } 
} 

方案2:

protected override void OnStart(string[] args) 
{ 
    // Assume all tasks implemented the same way. 
    // I believe we shouldn't await the tasks in this scenario. 
    var token = this._cancellationTokenSource.Token; 
    this.RunTask1(token); 
    this.RunTask2(token); 
    this.RunTask3(token); 
} 

private void RunTask1(CancellationToken token) 
{ 
    Task.Factory.StartNew(async() => 
     { 
      var telebot = new Telebot("SOMETHING"); 
      while(true) 
      { 
       // Some work... 
       // I/O dependent task. 
       var response = await telebot.GetUpdatesAsync(cancellationToken: token); 

       // 
       // Some other work 
       // may be some database calls using EF async operators. 
       // 
       await Task.Delay(TimeSpan.FromSeconds(1), token); 
      } 
     }, token); 
} 
+0

是不是更好返回任務分配給私人領域感激處置? – SerG

+1

你可以使用Task.Run(()=> doStuff(「hello world」));而不是Task.Factory.StartNew() –

+0

@AvsenevSlava據我所知,它們是平等的。 – mrtaikandi

回答

0

一個async方法同步運行,直到第一個await。之後,它將在ThreadPool線程上運行(除非有SynchronizationContext)。

因此,使用Task.Factory.StartNewTask.Run是不鼓勵的,因爲它試圖平行化大部分已經平行的東西。

但是,如果您有一個實質性的同步部分,則可以使用Task.Run(最好是Task.Factory.StartNew)來並行化它,但在調用方法時而不是在方法本身中應該這樣做。

所以,「情景1」比「情景2」更好。

我會盡管你不應該開火併忘記這些操作。您應該存儲的任務,等待它們完成,並觀察它們內部的任何異常,例如:

protected override void OnStart() 
{ 
    var token = _cancellationTokenSource.Token; 
    _tasks.Add(RunTask1(token)); 
    _tasks.Add(RunTask2(token)); 
    _tasks.Add(Task.Run(() => RunTask3(token))); // assuming RunTask3 has a long synchronous part 
} 

List<Task> _tasks; 

protected override void OnStop() 
{ 
    _cancellationTokenSource.Cancel(); 
    Task.WhenAll(_tasks).Wait(); 
} 
+0

謝謝。我假設第二個OnStart方法是OnStop。在這種情況下,我是否通過使OnStop方法異步並使用await Task.WhenAll(_tasks)來獲得任何內容? – mrtaikandi

+0

@Mohammadreza是的,OnStop。如果你真的可以改變它是一個異步方法並返回一個任務,那麼它會很好,但你不能改變簽名,因爲它是一個覆蓋。使它「異步無效」會更糟糕。 – i3arnon

+0

爲了澄清,如果我將基類void OnStop()更改爲不帶異步關鍵字的Task OnStop(),則從基類繼承的類可以使該方法異步。我對麼? – mrtaikandi

2

我無法解釋這是最好的一個,但在這裏是如何工作

1.場景代碼直到等待關鍵字由父線程執行,即應用程序的主線程。因此,一旦執行等待任務執行完成的事件處理由上下文保存即主線程上下文。

in 2.場景代碼它開始在任務工廠創建的線程上運行。在這裏,一旦執行等待任務執行完成由父母處理的事件,即由任務工廠創建的線程。

因此,在第一種情況下,如果您希望主要向主線程發佈某些內容,那麼主要適用於UI的應用程序。如果你想在後臺運行東西並且不需要父上下文,即主線程或UI線程,第二種情況是很好的。

相關問題