2012-04-22 33 views
0

我想爲某些同步代碼添加併發性,並發現該進程中的性能問題,這很難理解。Task.WaitAll()之間的性能差距問題,並順序執行Task.Wait

下面的代碼的運行結果是:

Mission Fibonacci1Async cost 9.4195388 seconds, value 75025 
Mission Fibonacci2Async cost 0.2260129 seconds, value 75025 

唯一不同是2RD功能添加了一行等待Task.WhenAll(新任務[] {T1,T2});,使演出增加40倍。

有人可以向我解釋嗎?

static Task<int> Fibonacci1Async(int n) 
    { 
     return Task.Run<int>(() => Fibonacci1(n)); 
    } 

    static int Fibonacci1(int n) 
    { 
     if (n == 0) return 0; 
     else if (n == 1) return 1; 
     else 
     { 
      var t1 = Fibonacci1Async(n - 1); 
      var t2 = Fibonacci1Async(n - 2); 
      return t1.Result + t2.Result; 
     } 
    } 

    static Task<int> Fibonacci2Async(int n) 
    { 
     return Task.Run<int>(() => Fibonacci2(n)); 
    } 

    static int Fibonacci2(int n) 
    { 
     if (n == 0) return 0; 
     else if (n == 1) return 1; 
     else 
     { 
      var t1 = Fibonacci2Async(n - 1); 
      var t2 = Fibonacci2Async(n - 2); 

      Task.WaitAll(new Task[] { t1, t2 }); 
      return t1.Result + t2.Result; 
     } 
    } 

    static void Benchmark(Func<int, Task<int>> func) 
    { 
     DateTime time = DateTime.Now; 
     var task = func(25); 
     task.Wait(); 
     TimeSpan cost = DateTime.Now - time; 
     Console.WriteLine("Mission {0} cost {1} seconds value {2}", func.Method.Name, cost.TotalSeconds, task.Result); 
    } 

    static void Main(string[] args) 
    { 
     Benchmark(Fibonacci1Async); 
     Benchmark(Fibonacci2Async); 
     Console.ReadKey(); 
     return; 
    } 

回答

1

我懷疑答案與Task.Wait inlining有關。

在表達式t1.Result + t2.Result中,+運算符從左到右評估它的參數(串行)。所以它會阻止t1然後t2

我猜測在你的系統上,大部分時間t1已經開始,但不是t2。在這種情況下,Task.WaitAll可以將當前線程池任務「嵌入」t2而不是啓動新任務,但+將在t1上阻塞。

這只是一個猜測;你應該使用一個分析器來找出究竟發生了什麼。

我無法在我的系統上重現此操作。我總是看到兩個版本大致相同,即使處理器親和力應用於流程。

P.S.命名約定Async在這裏並不適用。此代碼未使用async/await - 它使用任務並行庫。

+0

命名約定與await/async無關。這是一個實現細節。它指定調用者接收任務並獲得非阻塞行爲。 – usr 2012-04-22 13:46:08

+0

與返回類型組合的後綴'Async'意味着該方法使用基於任務的異步模式。我想你可以說這些'* Async'方法是TAP,但它們當然不是TAP實現的一個很好的例子。 – 2012-04-22 14:28:57

+0

例如,FileStream.ReadAsync內部不使用await。它使用IO完成端口。它沒有錯。來電者不需要知道。 – usr 2012-04-22 14:38:37