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

gsp*_*ger 1 .net c# asynchronous

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

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

我的问题是,每当我尝试调用它时,它似乎在调用 GetDataForAsyncCall2() 后从函数返回。但我想要从函数中得到的实际结果是 AsyncCall2。

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

Eri*_*ert 5

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

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

您可能需要对awaitC# 中的实际含义进行一些研究。简而言之,await意思是“如果此任务的结果不可用,则返回给我的调用者,以便它可以继续工作。在我等待的任务完成后的某个时间点在此点接听。” 即异步等待任务完成。

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

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

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

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

但我想要从函数中得到的实际结果是 AsyncCall2。

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

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

再次await强调:an是异步工作流中的一个点,我们知道在它之前,任务可能尚未完成,而在它之后,它肯定已完成。

你没问过的问题:

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

没有。这不仅违背了await用于管理延迟的整个目的。它也可能导致您永远等待。有关一些示例,请参阅http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html

这些例子很有教育意义;我会非常仔细地阅读它们,直到您彻底了解它们的await工作原理。