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

MBK*_*MBK 3 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();
    }
Run Code Online (Sandbox Code Playgroud)

据我所知,该程序的工作原理如下

  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步开始重复.

我的问题是

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

谢谢

Eri*_*ert 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. 最终,继续在适当的上下文上执行.延续是"回到循环的顶端",整个事情重新开始.

请注意,MyMethod返回的任务永远不会正常完成; 如果这些任务中的任何一个抛出异常,则异常完成.为简单起见,我忽略了示例中异常延续的检查,因为没有异常处理.

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

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

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

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

我认为你从根本上不明白"等待"意味着什么.您似乎认为"等待"意味着"异步启动此代码",但这根本不是什么意思.代码已经假设是异步的.Await 管理异步; 它不会创造它.

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

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