是否在异步方法中调用等待而没有等待仍然异步?

时间:2019-08-15 12:02:29

标签: c# asynchronous async-await task

考虑以下代码:

public static void Run() {
    DoStuffAsync();
}

public static async Task DoStuffAsync() {
     PerformCalc();
     await DoLongTaskAsync();
     PerformAnotherCalc();
}

比方说我打Run()。我对行为有一些疑问:

  1. 是否会在与调用PerformCalc()的线程相同的线程上同步调用Run()
  2. DoLongTaskAsync()被异步还是同步调用?换句话说,是否PerformAnotherCalc()会在DoLongTaskAsync()完成之前被调用?
  3. 随后,DoStuffAsync()方法是否可以在DoLongAsyncTask()执行完成之前返回?

4 个答案:

答案 0 :(得分:6)

异步方法始终 start 同步运行。魔术发生在await,但仅当await被赋予尚未完成的Task时。

在您的示例中,这是您致电Run()时发生的情况:

  1. 跳至DoStuffAsync()
  2. 跳至PerformCalc()
  3. 跳至DoLongTaskAsync()
  4. 如果 DoLongTaskAsync()是一个真正的异步操作并返回不完整的Task,则await会执行其工作,而DoStuffAsync()返回一个不完整的{ {1}}至Task
  5. 由于未等待任务,Run()完成。
  6. Run()完成后,DoLongTaskAsync()恢复,并跳到DoStuffAsync()

所有可以发生在同一线程上。

所以回答您的问题:

  1. 是的。如果它是PerformAnotherCalc()方法,那么它可能最终会消失并在其他线程上运行。但是它将在同一线程上同步启动。
  2. async将被异步调用,但是DoLongTaskAsync()不会在PerformAnotherCalc()完成之前被调用,因为您使用了DoLongTaskAsync()
  3. 是的。 await就是这样工作的。它将返回不完整的await(也就是说,仅当Task确实是异步的并且返回不完整的DoLongTaskAsync()时)。然后,Task完成后,DoLongTaskAsync()将从中断处继续执行。

答案 1 :(得分:2)

  
      
  1. 是否会在与调用Run()的线程相同的线程上同步调用PerformCalc()?
  2.   

是的

  
      
  1. 会以异步方式还是同步方式调用DoLongTaskAsync()?换句话说,在DoLongTaskAsync()完成之前会调用PerformAnotherCalc()吗?
  2.   

它将被同步调用,但是它可能在“长任务”操作完成之前返回Task。无论哪种方式,都将等待它返回的Task,因此直到从PerformAnotherCalc返回的Task都不会被调用DoLongTaskAsync

  
      
  1. 随后,DoStuffAsync()方法可以在DoLongAsyncTask()执行完成之前返回吗?
  2.   

DoStuffAsync到达第一个await时,该方法将返回(如果正在等待的Task处于挂起状态)。这就是async方法的工作方式-它们同步运行直到await的第一个Task挂起,然后返回Task,当整个过程完成时方法已执行。

如果可能是DoLongTaskAsync返回了已经完成的Task:在这种情况下,DoStuffAsync不会返回,直到PerformAnotherCalc返回。如果DoLongTaskAsync返回的Task仍在等待处理,则DoStuffAsync将在该点返回,并且将返回Task,一旦Task返回,则完成DoLongTaskAsync中的内容已完成, PerformAnotherCalc已返回。

答案 2 :(得分:1)

否则,请考虑以下方法:

public static void Run1() {
    DoStuffAsync();
    Console.WriteLine("Done");
}

public static async Task Run2() {
    await DoStuffAsync();
    Console.WriteLine("Done");
}

public static async Task DoStuffAsync() {
     PerformCalc();
     await DoLongTaskAsync();
     PerformAnotherCalc();
}

Run2中,可以保证在PerformAnotherCalc之后显示“完成”。在Run1中,“完成”将在PerformCalc之后但在PerformAnotherCalc之前显示(假设DoLongTaskAsync实际上是异步的,这取决于其实现)。

答案 3 :(得分:0)

所有呼叫都是同步的。如果返回的awaitable不完整,则await可以是异步的。