2017-08-14 49 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()'只是注册一个延续,然后返回代表延续完成的任务对象(这个任务对象直到原始任务完成时才能完成)。 –