当您等待C#中的异步任务时会发生什么?

时间:2018-11-27 11:57:30

标签: c# .net asynchronous

从我在C#的所有异步/等待教程中所了解的,我了解到,当我们定义一个异步方法时,这意味着我们可以在其中添加带有任务作为参数的await关键字,以使该方法返回到如果任务太长,请致电。然后,该方法可以在任务完成后恢复。

public void MyMainMethod()
{
   DoSomethingAsync();
   KeepOnDoingOtherStuff();
}

public async Task DoSomethingAsync()
{
   //Do whatever
   await LongOperation();
   // Rest of the method that is executed when the long operation is 
    //finished.

}

因此,在进行长时间操作时,等待时,DoSomething异步将手交给MainMethod,并执行KeepOnDoingOtherStuff。好

现在我的问题是我的DoSomethingAsync本身是否正在等待。在这种情况下:

public async void MyMainMethod()
{
   await DoSomethingAsync();

   //Here is a critical method that I want to execute only when 
     //DoSomethingAsync is finished

   CriticalStuff();
}

public async Task DoSomethingAsync()
{
   //Do whatever
   await LongOperation();
   // Rest of the method that is executed when the long operation is 
    //finished.

}

现在,我等待我的DoSomethingAsync,以确保它不会继续进行,但是问题是,当DoSomethingAsync()等待LongOperation()时,DoSomethingAsync()仍会提供给调用方,并且我的Main方法恢复,我不想要,因为它执行了我的关键任务。

我在异步逻辑中非常想念的东西,那么“等待”其中包含异步方法的方法又有什么意义呢?

非常感谢您解决我的问题。

先谢谢了。

2 个答案:

答案 0 :(得分:6)

我认为这里的不匹配来自这些词:

  

如果任务太长,则使方法返回到调用方。

await long 无关。它与异步有关。如果某事花费很长时间但在本地CPU上发生,那么请确保:它确实不适合await(尽管您可以使用await机器是方便的将其推送到工作线程,然后在完成时重新加入同步上下文线程的方法。

不过,更好的例子是当任务为 external 时;它可能是对SQL数据库的调用,redis的调用,通过http的调用,在某种IO层上的另一个进程的调用或等待套接字数据的调用。请注意,即使与物理本地SSD存储进行交谈也可能需要很长的等待时间,至少以CPU速度来衡量。当本地线程除了阻塞(等待回复)之外什么都不做时,那么:在许多情况下,线程可以做的事情要好得多。

对于客户端应用程序,那些“更好的事情”包括绘制UI并响应输入。对于服务器应用程序,那些“更好的事情”包括为其他并发请求/负载提供服务。


以这种方式进行测量时:await是一种编写需要外部数据的代码的有效方法,但又不想只是在当前线程中 block 到达。如果那不是您的情况:await可能不适合您。

答案 1 :(得分:1)

我正在讨论您的代码的这种变体:

public async void MyMainMethod()
{
   await DoSomethingAsync();

   //Here is a critical method that I want to execute only when 
     //DoSomethingAsync is finished

   CriticalStuff();
}

public async Task DoSomethingAsync()
{
   //Do whatever
   await LongOperation();
   // Rest of the method that is executed when the long operation is 
    //finished.

}

DoSomethingAsync返回时,它不只是盲目地将控制权交还给调用方法。它将其交给Task。如果该方法实际上是同步完成的,则将退回已完成的任务。否则,如果该方法仍有工作要做,则Task将运行,而不是尚未完成。

因此,DoSomethingAsync实际上触发了一些异步行为,并将尚未完成的Task返回给MainMain有什么用?它awaitawait就是该方法表示“除非可以等待的(通常是Task)完成,否则我将无济于事”。

如果Task尚未完成,则await不会再有任何进一步的进展(本身)。如果这是该方法中的第一个(必需)Main,则此时异步机制将启动,签署一个延续并从await本身返回。

直到您完成Task参数提供的await(或其他可等待),以及使用{{1 }}机械,直到该方法完全完成。

(在上面的描述中,我已经忽略了异常情况。这都是很高兴的事情)