2014-06-26 30 views
1

我得到了以下方法:執行所有任務,即使一個拋出異常

public async Task PublishAsync<TApplicationEvent>(TApplicationEvent e) 
    where TApplicationEvent : ApplicationEvent 
{ 
    using (var scope = _container.CreateScope()) 
    { 
     var implementations = scope.ResolveAll<IApplicationEventSubscriber<TApplicationEvent>>(); 
     var tasks = implementations.Select(x => x.HandleAsync(e)); 
     try 
     { 
      await Task.WhenAll(tasks); 
      EventPublished(this, new EventPublishedEventArgs(scope, e, true)); 
     } 
     catch 
     { 
      EventPublished(this, new EventPublishedEventArgs(scope, e, false)); 
      throw; 
     } 
    } 
} 

我以爲拋出異常之前的所有任務將被執行,但似乎該方法終止第一個任務時,拋出異常。

我可以配置WhenAll執行所有任務並在返回之前生成帶有所有故障的AggregateException嗎?

+0

那就是'WhenAll'做:「如果有任何的供應任務,在故障狀態下完成,返回的任務也將完成在故障狀態,其中它的異常將包含一套展開的聚集「)(http://msdn.microsoft.com/en-us/library/hh160384(v = vs.110).aspx) –

回答

8

這正是WhenAll確實做的。但是,當你拋出一個在其中有多個異常的聚合異常的任務時,它將重新拋出聚合異常中的第一個異常,而不是重新拋出聚合異常本身。 (這是因爲絕大多數拋出異常的任務在聚合中都不會有多個表達式,所以解開異常幾乎總是期望的行爲。)

只需在await之前持有對Task的引用以便稍後可以訪問聚合異常,或者根本不需要WhenAll的結果await,而是使用手動繼續。

+0

@jgauffin我建議你檢查所有的'WhenAll'完成時'tasks'中的任務。我的猜測是你沒有像你期望的那樣配置你的方法,如果這是你遇到的問題。 – Servy

+0

閱讀我的第二個更新。 '你的意思是'你沒有像你期望的那樣配置你的方法' – jgauffin

+0

@jgauffin你的'tasks'序列不包含你期望的所有操作,或者當你認爲它們沒有完成時。 – Servy

0

如果我運行下面的示例,所有的任務完成,但它仍然拋出,我相信這是預料:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 

namespace TaskWhenAllTest 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      try 
      { 
       Task task = Test(); 

       Task.WaitAll(new Task[] { task }); 

       Console.WriteLine(task.Status); 
      } 
      catch (Exception) 
      { 
       //Console.WriteLine(ex.ToString()); 
       Console.WriteLine("Task errored."); 
      } 

      Console.WriteLine("Done."); 
      Console.ReadKey(); 
     } 

     static async Task Test() 
     { 
      var task1 = Task.Factory.StartNew(() => { System.Threading.Thread.Sleep(1000); throw new Exception("Test1 exception"); }); 
      var task2 = Task.Factory.StartNew(() => { System.Threading.Thread.Sleep(500); Console.WriteLine("Task 2 complete."); }); 
      var task3 = Task.Factory.StartNew(() => { System.Threading.Thread.Sleep(250); Console.WriteLine("Task 3 complete."); }); 

      await Task.WhenAll(new Task[] {task1, task2, task3 }); 
     } 
    } 
} 
3

Task.WhenAll() - >創建任務,將完成全部供應的時任務已完成。

它將完成所有任務的執行,而不管個別任務中發生了什麼。

給定任務集合中的任務之一的異常不會阻止其他任務的執行。

 var tasks = new List<Task>(); 

     Task t1 = Task.Run(() => 
     { 
      throw new Exception("test1"); 
     }); 
     tasks.Add(t1); 

     Task t2 = Task.Run(() => 
     { 
      throw new Exception("test2"); 
     }); 
     tasks.Add(t2); 

     Task t3 = Task.Run(() => 
     { 
      Console.WriteLine("Pseudo Work"); 
     }); 
     tasks.Add(t3); 

     try 
     { 
      await Task.WhenAll(tasks); 
     } 
     catch (Exception ex) 
     { 
      // Only t1 & t2 will qualify and t3 will be successful (Pseudo Work will be printed on console) 
      var exceptions = tasks.Where(t => t.Exception != null).Select(t => t.Exception); 
     } 
相關問題