c#webapi:等待任务。运行vs更多颗粒等待

c#webapi:等待任务。运行vs更多颗粒等待,c#,asp.net-web-api,async-await,C#,Asp.net Web Api,Async Await,根据本文,我在WebApi控制器中使用async/await: 请看我控制器中的简化代码: DataBaseData = await Task.Run( () => GetDataFunction() ); GetDataFunction是一个函数,它将打开数据库连接、打开读卡器并从数据库中读取数据 在许多例子中,我看到它的处理方式不同。等待GetDataFunction本身。在功能中,每一步都在等待。 例如: connection.OpenAsync reader.readasy

根据本文,我在WebApi控制器中使用async/await:

请看我控制器中的简化代码:

DataBaseData = await Task.Run( () => GetDataFunction()  );
GetDataFunction是一个函数,它将打开数据库连接、打开读卡器并从数据库中读取数据

在许多例子中,我看到它的处理方式不同。等待GetDataFunction本身。在功能中,每一步都在等待。 例如:

  • connection.OpenAsync
  • reader.readasync
  • reader.IsDBNullAsync
为什么这是一种良好的做法?为什么不为整个数据库访问启动一个线程(使用Task.Run)

更新:
谢谢你的帮助。现在我明白了。我没有意识到,异步Api本身不会启动线程。这真的很有帮助:

我想您可能想知道为什么要使用

await Task.Run(() => GetDataFunction());
而不是

await GetDataFunction();
正如您在“备注”一节中所看到的,其中写道:

语言编译器使用Run(Func)方法来支持async和await关键字。它不打算直接从用户代码调用


这意味着,您应该使用
等待GetDataFunction

这是关于资源管理和共享的

使用
connection.Open()
方法时,调用该方法的线程必须等待连接实际打开。在等待时,它什么也不做,只消耗操作系统分配给它的CPU片。但是,当您
等待connection.OpenAsync()
时,线程将释放其资源,并且操作系统可以将它们重新分配给其他线程

现在,有一个陷阱:要从异步调用中获得实际收益,它们所需的时间应该比操作系统切换上下文所需的时间长,否则会导致应用程序性能下降

等待
connection.OpenAsync()
reader.ReadAsync()
等的做法是因为这些操作可能会长期运行。在de-database驻留在另一台计算机上且请求负载很重的系统中,连接到数据库并获取查询结果需要一些时间。与其在等待结果到达时阻塞CPU,为什么不将该时间片分配给另一个工作线程,该线程在调度程序队列中等待为另一个客户端呈现响应

现在,关于启动另一个线程进行数据访问:不要这样做。每个新线程都被分配了大约1MB的内存空间,因此除了在等待数据库操作完成时浪费CPU时间外,您还将浪费内存。此外,拥有如此大的内存占用将需要对垃圾收集器进行更多的运行,这将在运行时冻结所有线程


使用
Task.Run()
将计划线程池中某个线程上的数据访问操作,但在等待数据库服务器响应时,您将失去与另一个线程共享CPU时间的好处。

您链接到的文章指出:

您可以通过等待Task.Run开始一些后台工作,但这样做没有意义。事实上,这实际上会干扰ASP.NET线程池启发式,从而损害您的可伸缩性。。。一般来说,不要将工作排队到ASP.NET上的线程池

换句话说,避免执行
任务。在ASP.NET上运行

为什么这是一种良好的做法?为什么不为整个数据库访问启动一个线程(使用Task.Run)

这是因为异步API不使用其他线程。
async
/
await
的整个要点是释放当前线程;不要使用其他线程。我有一篇博客文章描述


因此,
Task.Run
(或自定义线程)方法将在从数据库获取数据时使用(阻止)线程。适当的异步方法(如EF6或ADO.NET异步API)不会;它们允许在请求等待数据库响应时,将请求线程用于其他请求。

这里解释如下:我不理解async/await是如何工作的。但我不明白为什么我需要WebApi控制器中的细粒度异步/等待处理。它用于确保请求线程返回到池中。然后等待任务。Run也会这么做。有人能解释一下为什么我会在这个问题上投反对票吗?好的,你说得对。不应使用Task.Run。尽管如此,如果我只是以通常的方式生成一个新线程呢?我的意思是,主要的问题是,是否有必要使用非常细粒度的处理并等待sql读取操作的每一步,或者在单独的线程中执行整个数据库操作也可以。这都是关于Webapi控制器中的请求池,而不是关于与UI相关的异步/等待。如果不更新任务中与GUI相关的项,则可以跨越所有数据库操作。但是建议在db-connection上使用
非异步
方法。谢谢!这篇文章帮助很大: