2017-08-14 98 views
2

我試圖鏈在一起的幾個異步方法,我創建,我相信有關於它如何工作鏈接異步方法

這裏是我的代碼表示對我而言有些根本性的誤解:

public async Task<bool> LoadFoo() 
{ 
    return await Foo.ReadAsync("bar").ContinueWith((bar) => 
    { 
     Foo.ReadAsync("baz").ContinueWith((baz) => 
     { 
      Foo.ReadAsync("qux").ContinueWith((qux) => 
      { 
       return true; 
      }); 

      return true; 
     }); 

     return true; 
    }); 
} 

public void LoadEverything() 
{ 
    LoadFoo().ContinueWith((blah) => 
    { 
     OtherLoadMethod(); 
    }); 
} 

現在我期待LoadEverything()被調用時,LoadFoo(「bar」,「baz」和「qux」)中的所有ReadAsync方法都將運行並完成,並且在它們全部完成之後,.Continue與在LoadEverything中將運行,以便在「bar」,「baz」和「qux」ReadAsync方法完成之前,OtherLoadMethod()不會執行。

我實際上看到的是LoadFoo被調用,然後OtherLoadMethod開始運行,最後在LoadFoo中完成(繼續執行「qux」ReadAsync)。

有人可以幫助澄清我的誤解嗎?爲什麼不會執行OtherLoadMethod等到ReadAsync(「qux」)完成並返回true?

+0

不要使用'ContinueWith';改用'await'。 –

回答

8

爲什麼不會執行OtherLoadMethod等到ReadAsync(「qux」)完成並返回true?

因爲這就是await的工作原理。您註冊的延續只是:延續。它們不會在當前方法中同步執行。您正在告訴框架當前任務完成時,應繼續執行。由ContinueWith()返回的Task對象允許您觀察完成是否以及何時發生。如果ContinueWith()方法被阻塞,直到繼續執行,則不需要返回Task對象。

同樣,您的LoadFoo()方法返回的Task<bool>表示該方法的整體完成,包括您要返回的await...ContinueWith()。該方法在繼續完成之前返回,如果需要等待延續完成,則調用者需要使用返回的任務。

所有這一切說,我不明白你爲什麼首先使用ContinueWith()。您顯然有權訪問await,這是處理延續的現代慣用方式。恕我直言,你的代碼應該是這個樣子(目前還不清楚爲什麼你返回Task<bool>代替Task,因爲返回值是永遠只能true,但我相信你可以自己計算的那部分):

public async Task<bool> LoadFoo() 
{ 
    await Foo.ReadAsync("bar"); 
    await Foo.ReadAsync("baz"); 
    await Foo.ReadAsync("qux"); 

    return true; 
} 

public async Task LoadEverything() 
{ 
    await LoadFoo(); 
    await OtherLoadMethod(); 
} 
+0

謝謝彼得。只是爲了確保我理解正確,等待不會阻止線程正確? 如果我要使用延續(例如,如果我需要使用其中一種方法的返回值),我想了解此評論: 「該方法在繼續完成之前返回,並且預計調用者將使用返回的任務,如果他們需要等待延續完成。「 不會調用LoadFoo()。ContinueWith(...)是否等待繼續完成的調用者? –

+0

_「等待不會阻塞線程」_ - 這是正確的。 'await'標誌方法_may_返回的方法中的一個點(如果該等待表達式已經完成,則該方法不會),在該等待時間完成時該點將被恢復(繼續)。該線程將在該點返回調用者,或者繼續執行當前方法。無論哪種方式,線程仍然暢通無阻 –

+0

_「不會調用LoadFoo()。ContinueWith(...)是否等待繼續完成的調用者?」_ - 否。這裏沒有等待。 'ContinueWith()'只是註冊一個延續,然後返回代表延續完成的任務對象(這個任務對象直到原始任務完成時才能完成)。 –