假设我有一个函数A,该函数使用了一个函数B,该函数使用了C等,
A -> B -> C -> D and E
现在假定函数D必须使用async/await
。这意味着我必须先使用async/await
来调用函数C
,然后再调用函数B
,依此类推。我了解这是因为它们彼此依赖,并且如果其中之一正在等待函数解析,然后传递,则它们都必须这样做。我可以做些什么来使它更清洁?
答案 0 :(得分:1)
有一种方法可以做到这一点,但是您将失去async-await的好处。
进行异步等待的原因之一是,如果您的线程必须等待另一个进程完成,例如对硬盘的读取或写入操作,数据库查询或获取某些Internet信息,则您的线程可能会做一些其他有用的事情,而不仅仅是闲着等待其他过程完成。
这是通过使用关键字await完成的。一旦线程看到等待状态。线程并没有真正地等待。相反,它会记住上下文(考虑变量值,部分调用堆栈等),并向上调用堆栈以查看调用方是否在等待。如果没有,它将开始执行这些语句,直到看到等待。它将再次进入调用堆栈,以查看呼叫者是否在等待中,等等。
一旦另一个进程完成,线程(或者可能是线程池中另一个充当原始线程的线程)在等待之后继续执行该语句,直到该过程完成或看到另一个等待为止。
要执行此操作,您的过程必须知道,当它看到等待时,需要保存上下文,并且线程的行为必须如上所述。这就是为什么您声明一个异步方法的原因。
这就是为什么典型的异步函数是命令其他进程进行冗长工作的函数的原因:磁盘访问,数据库访问,Internet通信。这些是典型的功能,您可以在标准的读/写功能旁边找到ReadAsync / WriteAsync。您还将在通常用于调用这些过程的类中找到它们,例如StreamReaders,TextWriters等。
如果您有一个非异步类,该类调用异步函数并等到异步函数完成后再返回,那么调用栈就可以看到是否有调用者-awaiting在这里停止:您的程序就好像没有在使用async-await一样。
快!
如果您启动了一个等待的任务,而没有等待它完成,并且在等待结果之前执行了其他操作,那么将执行该操作而不是闲置等待,否则线程将执行该操作使用了非异步版本。
ICollection<string> ReadData(...)
{
// call the async function, don't await yet, you'll have far more interesting things to do
var taskReadLines = myReader.ReadLinesAsync(...);
DoSomethingInteresting();
// now you need the data from the read task.
// However, because this method is not async, you can't await.
// This Wait will really be an idle wait.
taskReadLines.Wait();
ICollection<string> readLines= taskRead.Result;
return readLines();
}
您的呼叫者不会从异步等待中受益,但是,在尚未读取行的情况下,您的线程将能够做一些有趣的事情。