嵌套调用异步函数如何工作?

时间:2017-09-07 22:29:13

标签: c# asynchronous

我是异步编程的新手,我的问题可能看起来很傻。请问任何人,在下面的伪代码示例中解释异步调用是如何工作的?

    public async Task MyMethod()
    {
     while(true)
     {
      await Method1();
      //do something in MyMethod 
      await Task.Delay(10000);
     }
    }

    private async Task Method1()
    {
    //do something in Method1 before await
    await Method2();
    //do something in Method1 after await
    }

    private async Task Method2()
    {
    //do something in Method2 before await
    await LongRunMethod();
    }

根据我的理解,程序就像这样工作

  1. MyMethod()在无限循环中调用Method1()
  2. Method1()运行“在等待之前在Method1中执行某些操作”
  3. Method1()启动Method2()并将控制权返回给MyMethod()
  4. MyMethod()启动10000毫秒延迟并将控制权返回给其调用者
  5. Method2()完成“在await之前在Method2中执行某些操作”,启动LongRunMethod()并将控制权返回给MyMethod1()
  6. Method1()完成“等待后在Method1中执行某些操作”。之后有什么方法可以控制?
  7. LongRunMethod()完成其工作
  8. Method2()完成其工作。它是否将控制权返回给Method1()?
  9. 10000ms后,一切都从第1步开始重复。
  10. 我的问题是

    1. 以上步骤顺序是否正确?
    2. 在Method1()和Method2()完成第6步和第8步的工作后,哪些方法可以控制?
    3. 如果LongRunMethod()运行时间超过10000毫秒会发生什么?
    4. 谢谢

1 个答案:

答案 0 :(得分:6)

  

以上步骤顺序是否正确?

没有

正确的顺序是

  1. MyMethod调用Method1。
  2. Method1在调用Method2之前执行代码。
  3. Method1调用Method2。
  4. Method2在调用LongRunMethod之前执行代码。
  5. Method2调用LongRunMethod。
  6. LongRunMethod将任务返回给Method2。
  7. Method2询问任务是否完整。我们假设不是。
  8. 方法2注册“不再执行其他工作,然后将method2的任务标记为完成”作为刚刚返回的任务的继续,并将其任务返回到Method1。
  9. Method1询问刚从method2返回的任务。我们假设它不完整。它将等待之后发生的工作分配为method1的任务的继续,并将该任务返回给其调用者。
  10. MyMethod询问刚从Method1返回的任务。我们假设它不完整。它将该工作的剩余部分注册到任务的继续,并将该任务返回给其调用者。
  11. 那个来电者,无论是什么,都会做任何工作。
  12. 在将来的某个时刻,LongRunMethod的任务以异步方式完成,并请求在适当的上下文中恢复其继续。
  13. 最终上下文运行代码,并且它运行LongRunMethod任务的延续,回想起,该任务不起作用,然后将Method2任务标记为完成。
  14. 就是这样。 Method2的任务现在已经完成,因此它要求继续在适当的上下文中运行。
  15. 最终运行。回想一下,Method2任务的延续是运行Method1的其余部分。它会这样做,然后将Method1的任务标记为完成。这要求Method1的任务继续运行。
  16. 最终继续运行。它的延续是调用Task.Delay。
  17. Task.Delay返回任务。 MyMethod询问任务。它不完整。所以它签署了“回到循环的顶部”作为该任务的延续。然后它返回。
  18. 无论什么代码触发LongRunMethod的任务继续工作。在将来的某个时间点,延迟任务完成并请求继续执行。
  19. 最终,继续在适当的上下文中执行。延续是“回到循环的顶端”,整个事情重新开始。
  20. 请注意,MyMethod返回的任务永远不会正常完成;如果这些任务中的任何一个抛出异常,则异常完成。为简单起见,我忽略了示例中异常延续的检查,因为没有异常处理。

      

    在Method1()和Method2()完成工作后,哪些方法可以控制?

    Method2 的其余部分最终在Method2返回的任务完成后获得控制权。在Method1返回的任务完成后,MyMethod 最终获得控制权。计划延期的确切细节取决于代码运行的上下文;如果它们位于表单的UI线程上,那么它们与Web服务器上的工作线程非常不同。

      

    如果LongRunMethod()运行时间超过10000毫秒会发生什么?

    我认为你的意思是如果LongRunMethod返回的任务没有完成超过十秒钟会发生什么。那时没有什么特别有趣的事情。直到LongRunMethod的任务完成后才开始延迟。 您正在等待该任务

    我认为你从根本上不明白“等待”是什么意思。您似乎认为“等待”意味着“异步启动此代码”,但这根本不是什么意思。通过假设,代码已经异步。等待管理异步;它不会创建它。

    相反,等待是任务的操作员,如果此任务完成则意味着然后继续;如果此任务未完成,则将该方法的其余部分注册为该任务的延续,并尝试通过返回给您的调用者来查找此线程上的其他工作。

    在等待任务完成之前,await之后没有代码执行; await意味着异步等待任务完成。它并不意味着“异步启动此代码”。等待是声明异步工作流中的哪些点必须等待任务完成才能继续工作流。这就是它在名字中“等待”的原因。