async 方法是否应该始终调用 await,如果不是,这意味着什么?

Should async method always call await, if not what is the implication?

在这个例子中,

private async void Button1_Click(object sender, EventArgs e)
{
    if (condition) await Task.Run(Foo);
}

private void Foo()
{
    Thread.Sleep(5000);
}

有时条件为假,异步方法什么都不等待。但是考虑这个例子,

private async void Button1_Click(object sender, EventArgs e)
{
    await Task.Run(Foo);
}

private void Foo()
{
    if (condition) Thread.Sleep(5000);
}

始终等待该方法,即使条件为假。我想知道幕后发生了什么,如果一个比另一个更可取,我的意思是 objectively 如果有编译器优化使一个比另一个更可取。假设可以从任何线程检查条件,并且对性能的影响非常小。

似乎当条件检查被推迟时,总是有一个任务在等待,但是当它在处理程序中为 false 时,我的情况接近于异步方法缺少 await 运算符的情况,大约编译器警告我。所以它同时感觉是错误的和正确的。希望有人可以 objective 阐明这个问题。

方法上的 async 关键字仅向编译器指示,方法内的代码应转换为 state-machine,并在 await 处进行状态转换。

据我所知,唯一的 down-side 技术 async 方法不 await 任何东西,是 await 引入的少量开销=18=]。它应该没有负面影响,除了非常小的性能影响和一点点 memory-pressure,这在您的场景中很可能会被忽略。

Should async method always call await, if not what is the implication?

正如我所描述的 on my blogasync 方法总是同步开始执行,就像任何其他方法一样。 await 事情可能变得异步。

如果在没有 await 的地方采用代码路径(或者如果等待的任务已经完成),则该方法同步完成,并且 returns 一个 already-completed 任务它的来电者。这在实践中不是问题,因为“*Async”的意思是“可能是异步的”,而不是“必须是异步的”。

在这个具体示例中,您使用的是 async void,但如果这是一个被多次调用的 async Task 方法,在这种情况下我建议考虑返回 ValueTask 相反,这会在同步完成时为 Task 节省一些内存分配。

在您的特定情况下,Thread.Sleep(5000) 不是暂停执行的最佳方式。 Thread.Sleep(5000) 是旧的 API,它 阻塞 给定时间(5000 毫秒)的执行线程。 那是什么意思?这意味着该线程将无法用于其他任务。比方说,给定你的计算机 CPU 输出,你总共有 4 个线程,你将其中的 1 个锁定了 5000 毫秒 - 这 真的 很糟糕,尤其是如果它是一个 Web 应用程序必须处理并发 API 请求。用什么代替? await Task.Delay(5000) 它将“挂起”给定时间的执行,但线程将返回线程池并将可用于其他任务。

现在更接近你的问题了。将 non-asynchronous 代码包装到 Task 并等待 不会做任何事情。 Async/await 专为 I/O 操作而设计,专门用于不阻塞等待 I/O 完成的线程。将代码包装到 Tasknot waiting - 基本上是“即发即忘”,这意味着您的执行线程可能会继续执行下一个块而无需等待您的 Task方法来完成。为什么我说 可能 是因为如果 Task 中的代码包装器足够快它会同步工作