具有两个等待的异步调用的异步函数,其中第二个调用需要第一个调用的结果



所以我有一个函数,看起来像:

async Task DoSomething() {
var result = await GetDataForAsyncCall2();
if (result != null) {
await AsyncCall2(result.result1, result.result2);
}
}

我的问题是,每当我试图调用它时,它似乎在调用GetDataForAsyncCall2()后从函数返回。但我希望函数的实际结果是AsyncCall2。

为什么我的函数会在第一次等待之后返回,或者我如何确保在函数返回之前运行第二次等待?

为什么我的函数会在第一次等待之后返回?

你问这个问题的事实表明,你对await的作用一定有一些完全错误的信念。这就像是在问为什么return会返回。awaitreturn的一种。(就像yield return是迭代器块中的一种返回一样。yield returnawait在某种程度上本质上是相同的;它们都是工作流返回给调用方并注册方法的其余部分以在未来运行的点。)

你可能需要研究一下await在C#中的实际含义。简单地说,await的意思是"如果此任务的结果不可用,那么返回给我的调用者,以便它可以继续工作。在我等待的任务完成后的某个时间点,在这个时间点接电话。"也就是说,异步等待任务完成。

如果这是你在方法中点击的第一个等待,那么返回给调用者的将是一个代表方法本身的任务,因为现在也没有完成,调用者可能想等待它。

但仅仅简单的解释可能是不够的。你应该阅读一些关于它如何工作的文章或教程,这样你才能更有效地使用它。

如何确保在函数返回之前运行第二个等待?

你没有。这是故意的。等待允许您识别异步工作流中的点,这些点是(1)高延迟操作,以及(2)在工作流的其余部分执行之前必须完成的操作。等待序列正确地表示了第二个高延迟任务对第一个任务的数据依赖性。系统按设计工作。

但我希望函数的实际结果是AsyncCall2。

我假设您所追求的"结果"是一个副作用,因为没有从AsyncCall2中提取任何值,并且您有一个从该方法返回的无值任务。

这正是你得到的。您的方法返回一个任务,AsyncCall2返回的任务完成后,该任务将在将来的某个时间点标记为已完成。如果您的调用者希望在将来异步等待,那么它应该await返回的任务。

同样:await是异步工作流中的一个点,我们知道在它之前,任务可能还没有完成,在它之后,它肯定已经完成。

一个你没有问的问题:

我应该使用.Result或类似功能同步等待高延迟操作来解决问题吗?

。这不仅违背了使用await管理延迟的全部目的。它也可能导致你永远等待。看见http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html例如。

这些例子具有很强的教育意义;我会非常仔细地阅读,直到你完全理解await是如何工作的。

最新更新