c# - 我应该在控制器中使用 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();
}
从我的想法来看,第二种方法是使用“异步”声明的过度杀伤力吗?第一种方法在得到结果之前不会返回任何东西。
谢谢
解决方案
如果您阅读有关I/O 线程的这篇文章,您会更好地理解这一点
要正确使用 .NET 的异步和并行特性,您还应该了解I/O 线程的概念。
并非程序中的所有内容都会消耗 CPU 时间。当线程试图从磁盘上的文件中读取数据或通过网络发送 TCP/IP 数据包时,它所做的唯一事情就是将实际工作委托给设备(磁盘或网络适配器)并等待结果。
I/O 线程是一种抽象,旨在将与设备的工作隐藏在一个简单而熟悉的概念后面。这里的要点是您不必以不同的方式使用这些设备,您可以将它们内部的管道视为通常的 CPU 消耗线程。同时,与 CPU 绑定线程相比,I/O 线程非常便宜,因为实际上它们只是对设备的请求
所以用第一种方法,你没有使用 I/O 线程,但是用第二种方法,它便宜得多。
在您的情况下,当访问数据库时,您实际上是在执行 I/O(网络)操作。通过使用异步编程,您在 I/O 线程上等待 I/O(数据库读取)操作完成,而不会阻塞线程。
编辑(在利亚姆的评论之后)
另一个有趣的阅读是深度异步
在整个过程中,一个关键的要点是没有线程专门用于运行任务。尽管工作是在某些上下文中执行的(也就是说,操作系统确实必须将数据传递给设备驱动程序并响应中断),但没有专门用于等待来自请求的数据返回的线程。这允许系统处理更大的工作量,而不是等待一些 I/O 调用完成。
有关更多信息,请在此处查看异步开销
- 如果异步方法同步完成,则性能开销相当小。
- 如果异步方法同步完成,将发生以下内存开销:对于异步任务方法没有开销,对于异步任务方法,每个操作的开销为 88 字节(在 x64 平台上)。
- ValueTask 可以消除上面提到的同步完成的异步方法的开销。
- 如果方法同步完成,则基于 ValueTask 的异步方法比基于 Task 的方法快一点,否则慢一点。
- 等待未完成任务的异步方法的性能开销要大得多(x64 平台上每个操作约 300 字节)。
推荐阅读
- python - 错误:只能将 str(不是“列表”)连接到 str
- flutter - Flutter TextField - textAlignVertical 不起作用
- vue.js - 如何在不添加路由到 vue 中的历史记录的情况下重定向到登录?
- android - Android Studio - Gradle 构建
- wordpress - Wordpress 子页面不切换名称
- parsing - 如何检查语法是否为 SLR(1)?
- laravel - Laravel 数据库迁移为 $table->morphs() 命名?
- javascript - 在反应中使用 babel 时如何解决“错误”找不到模块'babel-preset-react'”
- laravel - Laravel 中“dropColumn”上的“一般错误:1 个外键不匹配”
- c++ - 需要帮助理解 NS-3 中的特定代码