从我在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方法恢复,我不想要,因为它执行了我的关键任务。
我在异步逻辑中非常想念的东西,那么“等待”其中包含异步方法的方法又有什么意义呢?
非常感谢您解决我的问题。
先谢谢了。
答案 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
返回给Main
。 Main
有什么用?它await
。 await
就是该方法表示“除非可以等待的(通常是Task
)完成,否则我将无济于事”。
如果Task
尚未完成,则await
不会再有任何进一步的进展(本身)。如果这是该方法中的第一个(必需)Main
,则此时异步机制将启动,签署一个延续并从await
本身返回。
直到您完成Task
参数提供的await
(或其他可等待),以及使用{{1 }}机械,直到该方法完全完成。
(在上面的描述中,我已经忽略了异常情况。这都是很高兴的事情)