【发布时间】:2019-09-21 08:34:00
【问题描述】:
如果这是一个愚蠢的问题(或重复),我很抱歉。
我有一个函数A:
public async Task<int> A(/* some parameters */)
{
var result = await SomeOtherFuncAsync(/* some other parameters */);
return (result);
}
我还有另一个函数B,调用A但没有使用返回值:
public Task B(/* some parameters */)
{
var taskA = A(/* parameters */); // #1
return (taskA);
}
请注意,B 未声明为 async,并且未等待对 A 的调用。对A 的调用不是一劳永逸的调用——B 由C 调用,如下所示:
public async Task C()
{
await B(/* parameters */);
}
请注意,在 #1 处,没有 await。我有一位同事声称这使得对A 的调用是同步的,并且他不断提出Console.WriteLine 日志,这似乎证明了他的观点。
我试图指出,仅仅因为我们不等待 B 中的结果,任务链 等待并且 A 中的代码性质不会改变因为我们不等待它。由于不需要来自A 的返回值,因此无需在调用站点等待任务,只要链上的某个人等待它(这发生在C)。
我的同事非常坚持,我开始怀疑自己。是不是我的理解错了?
【问题讨论】:
-
我很想看到
Console.WriteLine代码似乎证明这是同步的。 -
“坚持”与“明显正确”不同。您的同事可能有观点,或者可能完全错了。 (您设计的示例也可能在整个操作中删除了其他内容。)从等式中删除个性并创建一个测试来演示您期望代码执行的操作。立即结束(不读取输入)的控制台应用程序对此特别有用,因为如果异步操作需要一些时间并且没有等待,那么应用程序将在可以观察到该操作的副作用之前终止。
-
@David 实际上在a question last week 中有一个很好的例子,只是因为
Main方法是async void,因此框架不知道任何任务仍在运行和终止该程序。它异步运行,即使框架没有等待它。 -
@GabrielLuci:很好的例子。我已经看到了一些有趣的“测试”,我同样坚持不懈的同事,我在下面为 Eric Lippert 的答案添加了书签,以备下次发生时参考。上一个项目的一个例子是一位程序员,他确信他的“即发即弃”代码(在同步接口后面隐藏一些异步的东西,从不等待它)总是有效的,因为它在他的 WinForms 应用程序中“有效”。这只是一个巧合,因为该操作在他关闭应用程序的时间内“起作用”。在控制台应用程序中,操作从未完成。
-
@David 为什么你说这个例子是做作的?它准确地演示了所讨论的场景(当然,实际功能不同,它们采用实际参数等)
标签: c# .net asynchronous async-await