首页 > 解决方案 > 我应该在控制器中使用 async/await 吗?

问题描述

我在 YouTube 上观看了 Les Jackson 的一些视频,介绍了如何创建 .net 核心 API。Les 将这种方法用于他的控制器中的方法

    public ActionResult<IEnumerable<Command>> GetAllCommands()
    {
        var commandItems = _repository.GetAppCommands();
        return Ok(commandItems);
    }

但是我刚刚阅读了使用这种方法的书中的一篇文章

public async Task<ActionResult<IEnumerable<Data.CityDataClass>>> GetCities()
{
    return await _repository.GetCities();
}

从我的想法来看,第二种方法是使用“异步”声明的过度杀伤力吗?第一种方法在得到结果之前不会返回任何东西。

谢谢

标签: c#async-awaittask-parallel-library

解决方案


如果您阅读有关I/O 线程的这篇文章,您会更好地理解这一点

要正确使用 .NET 的异步和并行特性,您还应该了解I/O 线程的概念。

并非程序中的所有内容都会消耗 CPU 时间。当线程试图从磁盘上的文件中读取数据或通过网络发送 TCP/IP 数据包时,它所做的唯一事情就是将实际工作委托给设备(磁盘或网络适配器)并等待结果。

I/O 线程是一种抽象,旨在将与设备的工作隐藏在一个简单而熟悉的概念后面。这里的要点是您不必以不同的方式使用这些设备,您可以将它们内部的管道视为通常的 CPU 消耗线程。同时,与 CPU 绑定线程相比,I/O 线程非常便宜,因为实际上它们只是对设备的请求

所以用第一种方法,你没有使用 I/O 线程,但是用第二种方法,它便宜得多。

在您的情况下,当访问数据库时,您实际上是在执行 I/O(网络)操作。通过使用异步编程,您在 I/O 线程上等待 I/O(数据库读取)操作完成,而不会阻塞线程。

编辑(在利亚姆的评论之后)

另一个有趣的阅读是深度异步

在整个过程中,一个关键的要点是没有线程专门用于运行任务。尽管工作是在某些上下文中执行的(也就是说,操作系统确实必须将数据传递给设备驱动程序并响应中断),但没有专门用于等待来自请求的数据返回的线程。这允许系统处理更大的工作量,而不是等待一些 I/O 调用完成。

有关更多信息,请在此处查看异步开销

  1. 如果异步方法同步完成,则性能开销相当小。
  2. 如果异步方法同步完成,将发生以下内存开销:对于异步任务方法没有开销,对于异步任务方法,每个操作的开销为 88 字节(在 x64 平台上)。
  3. ValueTask 可以消除上面提到的同步完成的异步方法的开销。
  4. 如果方法同步完成,则基于 ValueTask 的异步方法比基于 Task 的方法快一点,否则慢一点。
  5. 等待未完成任务的异步方法的性能开销要大得多(x64 平台上每个操作约 300 字节)。

推荐阅读