2012-04-20 56 views
2

我想學習如何併發添加一些同步程序,並採取斐波那契算法爲例。我編寫了這些代碼,但是我發現它沒有任何併發​​性。所有代碼在單個線程中運行直到完成。任何人都可以向我解釋爲什麼它不反映異步?如何用C#異步併發添加到同步程序/等待

async static Task<int> Fibonacci(int n) 
    { 
     if (n == 0) { return 0; } 
     else if (n == 1) { return 1; } 
     else 
     { 
      var t1 = Fibonacci(n - 1); 
      var t2 = Fibonacci(n - 2); 
      return (await t1) + (await t2); 
     } 
    } 

    static int Main(string[] args) 
    { 
     var fib = Fibonacci(25); 
     fib.Wait(); 
     Console.WriteLine(fib.Result); 
     Console.ReadKey(); 
     return 0; 
    } 

在邁克爾的提示下,我嘗試在異步函數創建任務,和它的作品。 但我注意到一個異步函數返回一個Task類型值,它與Task.Run()相同。這兩個任務都將立即運行,但t1不會自動運行到新線程。 所以任何人都可以告訴我,這兩個任務有什麼不同。我可以使異步函數自動運行到新線程嗎?

async static Task<string> Async1() 
    { 
     return DateTime.Now.ToString(); 
    } 
    static void Main(string[] args) 
    { 
     Task<string> t1 = Async1(); 
     Task<string> t2 = Task.Run<string>(() => { return DateTime.Now.ToString(); }); 
    } 
+0

你是什麼意思它沒有反應?當你運行你的程序時會發生什麼? – gideon 2012-04-20 12:08:03

+0

你如何期待它作出反應? – 2012-04-20 12:11:36

+0

我希望你知道這是一個非常低效的算法(提示:計算fib(20)的計算頻率)?好吧,測試異步工作很好(需要很長時間:-))。 – 2012-04-20 12:12:07

回答

5

首先,您正在使用.NET 4.5的async/await模型的實驗性CTP。在這樣的環境中,你應該預料到事情會表現不好。

其次,你知道,你在年底無限期地睡着了嗎?

三,你的應用程序基本上是同步的。你做了一個異步任務,然後立即等待它。 async/await模型不會添加併發性,只會增加異步性。它只是讓您的應用程序在做多件事情時做出反應;它不會自動並行化。這就是爲什麼你的應用程序就像是同步的。

0

你是不是在線程池開始任務的。等待不會默認引入並行。

將其更改爲:

 var t1 = Task.Factory.StartNew(() => Fibonacci(n - 1)).Unwrap(); 
     var t2 = Task.Factory.StartNew(() => Fibonacci(n - 2)).Unwrap(); 

這是效率不高,因爲它可以得到的,但它會幫助您開始。

2

這種行爲有兩個原因。

首先,異步方法同步運行,直到他們必須評估一個等待聲明。在等待之前您正在遞歸,所以在等待任何事情之前,所有遞歸都將同步完成。

其次,如果等候的任務已經完成,然後等待它們可以同步運行。您的代碼永遠不會創建尚未完成的任務。它可以在任務中同步包裝並返回0或1,或者同步添加兩個同步完成的任務並返回該結果。

您需要在某處引入非同步方面。例如:

async static Task<int> Fibonacci(int n) 
{ 
    if (n == 0) { return 0; } 
    else if (n == 1) { return 1; } 
    else 
    { 
     // run one of the recursions concurrently 
     var t1 = Task.Factory.StartNew(() => Fibonacci(n - 1)); 
     var t2 = Fibonacci(n - 2); 
     return (await (await t1)) + (await t2); 
    } 
} 
0
private async Task<int> ComputeFibAsync(int n) 
    { 
     return await Task.Run(
      async() => 
      { 
       if (n < 2) 
       { 
        return 1; 
       } 
       else 
       { 
        var result = await Task.WhenAll<int>(ComputeFibAsync(n - 1), ComputeFibAsync(n - 2)); 
        return result[0] + result[1]; 
       } 
      } 
      ); 
    }