为什么我要返回 Task<IActionResult>在控制器中? [英] Why should I return Task&lt;IActionResult&gt; in a Controller?

查看:35
本文介绍了为什么我要返回 Task<IActionResult>在控制器中?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以我已经尝试掌握了很长一段时间,但看不到将每个控制器端点声明为异步方法的意义.

So I have been trying to get the grasp for quite some time now but couldn't see the sense in declaring every controller-endpoint as an async method.

让我们看一个 GET-Request 来形象化问题.

Let's look at a GET-Request to visualize the question.

这是我处理简单请求的方式,只需完成工作并发送响应即可.

This is my way to go with simple requests, just do the work and send the response.

[HttpGet]
public IActionResult GetUsers()
{
      // Do some work and get a list of all user-objects.
      List<User> userList = _dbService.ReadAllUsers(); 
      return Ok(userList);
} 

下面是我经常看到的 async Task 选项,它的作用与上面的方法相同,但方法本身返回一个 Task.人们可能会认为,这个更好,因为您可以有多个请求进入并且它们会异步处理但我测试了这种方法和上面的方法,结果相同.两者都可以同时接受多个请求.那么为什么我应该选择这个签名而不是上面的签名呢?我只能看到这样的负面影响,例如由于异步而将代码转换为状态机.

Below is the async Task<IActionResult> option I see very often, it does the same as the method above but the method itself is returning a Task. One could think, that this one is better because you can have multiple requests coming in and they get worked on asynchronously BUT I tested this approach and the approach above with the same results. Both can take multiple requests at once. So why should I choose this signature instead of the one above? I can only see the negative effects of this like transforming the code into a state-machine due to being async.

[HttpGet]
public async Task<IActionResult> GetUsers()
{
      // Do some work and get a list of all user-objects.
      List<User> userList = _dbService.ReadAllUsers(); 
      return Ok(userList);
} 

下面的这种方法也是我无法理解的.我看到很多代码都具有这种设置.一种 async 方法,它们 await 然后返回结果.像这样等待会使代码再次顺序化,而不是具有多任务/多线程的好处.我错了吗?

This approach below is also something I don't get the grasp off. I see a lot of code having exactly this setup. One async method they await and then returning the result. Awaiting like this makes the code sequential again instead of having the benefits of Multitasking/Multithreading. Am I wrong on this one?

[HttpGet]
public async Task<IActionResult> GetUsers()
{
      // Do some work and get a list of all user-objects.
      List<User> userList = await _dbService.ReadAllUsersAsync(); 
      return Ok(userList);
} 

如果你能用事实来启发我,我就可以继续像现在这样发展,或者知道由于误解了这个概念,我一直在做错,那就太好了.

It would be nice if you could enlighten me with facts so I can either continue developing like I do right now or know that I have been doing it wrong due to misunderstanding the concept.

推荐答案

请阅读 同步与异步请求处理"ASP.NET 上的 Async/Await 简介部分.

两者都可以同时接受多个请求.

Both can take multiple requests at once.

是的.这是因为 ASP.NET 是多线程的.因此,在同步情况下,您只需有多个线程调用相同的操作方法(在不同的控制器实例上).

Yes. This is because ASP.NET is multithreaded. So, in the synchronous case, you just have multiple threads invoking the same action method (on different controller instances).

对于非多线程平台(例如 Node.js),您必须使代码异步以处理同一进程中的多个请求.但在 ASP.NET 上它是可选的.

For non-multithreaded platforms (e.g., Node.js), you have to make the code asynchronous to handle multiple requests in the same process. But on ASP.NET it's optional.

像这样等待会使代码再次顺序化,而不是拥有多任务/多线程的好处.

Awaiting like this makes the code sequential again instead of having the benefits of Multitasking/Multithreading.

是的,它是顺序,但不是同步.在 async 方法一次执行一个语句的意义上,它是 sequential,并且该请求在 async 方法完成之前不会完成.但它不是同步——同步代码也是顺序的,但它阻塞一个线程直到方法完成.

Yes, it is sequential, but it's not synchronous. It's sequential in the sense that the async method executes one statement at a time, and that request isn't complete until the async method completes. But it's not synchronous - the synchronous code is also sequential, but it blocks a thread until the method completes.

那我为什么要选择这个签名而不是上面的那个?

So why should I choose this signature instead of the one above?

如果您的后端可以扩展,那么异步操作方法的好处是可扩展性.具体来说,异步操作方法在异步操作进行时产生它们的线程 - 在这种情况下,GetUsers 在数据库执行查询时不占用线程.

If your backend can scale, then the benefit of asynchronous action methods is scalability. Specifically, asynchronous action methods yield their thread while the asynchronous operation is in progress - in this case, GetUsers is not taking up a thread while the database is performing its query.

在测试环境中很难看到好处,因为您的服务器有空闲线程,因此调用异步方法 10 次(占用 0 个线程)和调用同步方法 10 次(占用 0 个线程)之间没有明显区别最多 10 个线程,还有 54 个空闲线程).您可以人为限制 ASP.NET 服务器中的线程数,然后进行一些测试看看区别.

The benefit can be hard to see in a testing environment, because your server has threads to spare, so there's no observable difference between calling an asynchronous method 10 times (taking up 0 threads) and calling a synchronous method 10 times (taking up 10 threads, with another 54 to spare). You can artificially restrict the number of threads in your ASP.NET server and then do some tests to see the difference.

在现实世界的服务器中,您通常希望使其尽可能异步,以便您的线程可用于处理其他请求.或者,如此处:

In a real-world server, you usually want to make it as asynchronous as possible so that your threads are available for handling other requests. Or, as described here:

请记住,异步代码不会取代线程池.这不是线程池异步代码;它是线程池异步代码.异步代码允许您的应用程序最佳地利用线程池.它使用现有的线程池并将其变为 11.

Bear in mind that asynchronous code does not replace the thread pool. This isn’t thread pool or asynchronous code; it’s thread pool and asynchronous code. Asynchronous code allows your application to make optimum use of the thread pool. It takes the existing thread pool and turns it up to 11.

记住如果"以上;这尤其适用于现有代码.如果您只有一个 SQL 服务器后端,并且几乎所有操作都查询数据库,则将它们更改为异步 可能没有用,因为可扩展性瓶颈通常是 db 服务器而不是 web 服务器.但是,如果您的 Web 应用可以使用线程来处理非数据库请求,或者如果您的数据库后端是可扩展的(NoSQL、SQL Azure 等),那么将操作方法​​更改为异步可能会有所帮助.

Bear in mind the "if" above; this particularly applies to existing code. If you have just a single SQL server backend, and if pretty much all your actions query the db, then changing them to be asynchronous may not be useful, since the scalability bottleneck is usually the db server and not the web server. But if your web app could use threads to handle non-db requests, or if your db backend is scalable (NoSQL, SQL Azure, etc), then changing action methods to be asynchronous would likely help.

对于新代码,我默认推荐异步方法.异步可以更好地利用服务器资源,并且更适合云计算(即,即用即付托管的成本更低).

For new code, I recommend asynchronous methods by default. Asynchronous makes better use of server resources and is more cloud-friendly (i.e., less expensive for pay-as-you-go hosting).

这篇关于为什么我要返回 Task<IActionResult>在控制器中?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆