抱歉如果这是个愚蠢的问题。
这不是一个愚蠢的问题,它是一个重要的问题。
我有一个同事声称这会使调用A异步化,并且他一直在使用Console.WriteLine日志来证明他的观点。
那就是根本的问题所在,你需要教育你的同事,让他们停止误导自己和其他人。在C#中,没有所谓的异步调用。调用永远不会是异步的。跟我说:在C#中,调用不是异步的。在C#中,当你调用一个函数时,在计算完所有参数之后,该函数立即被调用。
如果你的同事或你认为有异步调用这样的事情,那么你将面临痛苦的世界,因为你对异步工作方式的信仰将与现实非常脱节。
那么,你的同事是正确的吗?当然是的。调用A是同步的,因为所有函数调用都是同步的。但是,他们相信存在“异步调用”的事实意味着他们在C#中对异步工作原理的认识是错误的。
如果特别是你的同事认为await M()会使对M()的调用“异步化”,那么你的同事是大错特错了。await是一个运算符。确实是一个复杂的运算符,但它是一个运算符,并且作用于值。await M()和var t = M(); await t;是一样的。等待发生在调用之后,因为await作用于返回的值。await不是编译器“生成对M()的异步调用”的指令或任何类似的东西;异步调用不存在。
如果这是他们错误信仰的本质,那么你有机会告诉你的同事await的含义。await意味着简单而强大的事情。它的意思是:
- 查看我正在操作的任务。
- 如果任务异常完成,则抛出该异常。
- 如果任务正常完成,则提取该值并使用它。
- 如果任务未完成,则将该方法的其余部分注册为等待任务的继续,并返回表示此调用的不完整异步工作流程的新任务到我的调用者。
那就是
await
所做的全部内容。它只是检查任务的内容,如果任务未完成,则会说“好吧,在该任务完成之前,我们无法在此工作流程上取得任何进展,因此返回给我的调用者,他将为此CPU找到其他事情做”。
引用:“A”内部代码的性质并不因为我们不等待它而改变。
这是正确的。我们同步调用
A
,它返回一个
Task
。调用站点后的代码直到
A
返回才运行。
A
有趣的地方在于
A
允许向其调用者返回不完整的Task
,该任务表示异步工作流中的节点。 工作流已经是异步的,正如您所指出的,对于
A
来说,您对其返回值进行的任何操作都没有影响,即使在它返回后你不知道是否会
await
返回的
Task
。
A
只要能运行就会一直运行,然后它会返回一个已正常完成的任务、已异常完成的任务或不完整的任务。但是,调用站点上执行的任何操作都不会改变这一点。
引用:“由于不需要从A返回值,因此在调用站点不需要等待任务。”
正确。
引用:“只要链条上有人等待它(在C中发生),在调用站点就不需要等待任务。”
现在你把我弄丢了。为什么有人必须等待
A
返回的
Task
?
说出你为什么认为某人需要await
该Task
,因为你可能有错误的信念。
引用:“我的同事非常坚持,我开始怀疑自己。我的理解是否有误?”
你的同事几乎肯定是错的。你的分析在你说每个
Task
都需要
await
的那个部分似乎是正确的,但这并不正确。不
await
一个
Task
是很奇怪的,因为这意味着你编写了一个程序,在这个程序中你启动了一项操作,但并不关心它何时或如何完成,这确实让人感觉不太好。但并没有要求每个
Task
都必须
await
。如果你认为有这种要求,请再次说明你的想法,我们会搞清楚的。
Console.WriteLine
的代码,它似乎证明这是同步的。 - juharrMain
方法是async void
,所以框架不知道是否还有任务在运行并终止了程序。尽管框架没有等待它,但它仍在异步运行。 - Gabriel Luci