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

时间:2017-01-30 23:19:41

标签: c# .net asynchronous

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

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

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

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

1 个答案:

答案 0 :(得分:4)

  

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

您提出问题这一事实表明您必须对await所做的事情有一些完全错误的信念。这就像问return为什么返回。 await是一种return。 (就像yield return是迭代器块中的一种返回。yield returnawait在某种程度上基本相同;它们都是工作流返回其调用者的点并注册该方法的其余部分以便将来运行。)

您可能需要对await在C#中的实际含义进行一些研究。简而言之,await表示"如果此任务的结果不可用,则返回我的调用者,以便它可以继续工作。在我等待完成的任务完成后,将来的某个时间拿起。"也就是说,异步等待以完成任务。

如果这是第一次等待你在方法中命中,则返回给调用者的东西将是表示方法本身的任务,因为现在也不完整,并且调用者可能想要等待它。

但这个简短的解释可能还不够。您应该阅读一些有关其工作原理的文章或教程,以便您可以更有效地使用它。

  

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

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

  

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

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

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

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

你没有问的问题:

  

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

即可。这不仅违背了使用await来管理延迟的整个目的。它也可以让你永远等待。有关示例,请参阅http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html

这些例子具有很高的教育意义;我会仔细阅读非常,直到您完全理解await的工作方式。