【问题标题】:Should I use asynchronous methods in controllers of ASP.NET Web API我应该在 ASP.NET Web API 的控制器中使用异步方法吗
【发布时间】:2015-08-09 04:49:12
【问题描述】:

我在读一本书,发现当我们创建或替换资源时 put 动词使用相同的 URI,而帖子创建新资源的标识符。

其实,

  1. 这是否意味着控制器 (apicontroller) 中的发布操作总是会创建资源的新实例?
  2. 它会创建一个新的独立线程吗?
  3. 我不必担心将控制器中的方法声明为异步,因为它会为任何 http 请求创建一个新线程?
  4. 对于 put 操作,我是否需要将我的方法声明为异步以避免在使用 Web 资源时出现锁定?

【问题讨论】:

  • 我不认为方法上的动作动词与线程的处理有任何关系

标签: c# asp.net rest asp.net-web-api


【解决方案1】:

1) 这是否意味着控制器(apicontroller)中的发布操作总是会创建资源的新实例?

2) 它会创建一个新的独立线程吗?

是的。但请记住,方法上的动作动词与线程的处理无关。在对 API 的任何调用中,都会创建一个新线程,或者请求将使用线程池中的现有线程。

3) 我不必担心将控制器中的方法声明为异步,因为它会为任何 http 请求创建一个新线程?

简短的回答是,如果您关心缩放,则应该始终编写异步方法。阅读长篇故事了解更多详情。

4) 对于 PUT 操作,我是否需要将我的方法声明为异步以避免在使用 Web 资源时锁定?

正如我之前所说,您的操作是 PUT 还是 POST 并不重要。如果您进行阻塞 I/O 操作(例如访问数据库),最好使用异步方法。

说来话长

基于专门支持 REST 的 ASP.NET Web API 的 Web 服务使用 .NET 线程池来响应请求。但是,仅仅因为服务本质上是多线程的,并不能使它们在同时发出大量请求时进行扩展。线程被池化而不是动态创建的真正原因是因为它们在内存和 CPU 利用率方面都是极其昂贵的资源。例如,除了寄存器集上下文和线程属性之外,每个线程还消耗大约 1 MB 的堆栈空间。

所以一旦一个线程完成了它的工作,它会保持活动状态大约一分钟,如果另一个请求到达,等待的线程可以用来服务它。这意味着如果在执行服务请求期间,另一个请求到达,将从线程池中检索一个额外的线程来服务第二个请求。如果没有可用的线程,将从头开始创建一个,这可能需要 500 毫秒,在此期间请求将被阻塞。如果您有大量需要很长时间才能完成的操作请求,则会创建越来越多的线程,从而消耗额外的内存并对服务的性能产生负面影响。

故事的寓意是:不要从服务操作中阻塞正在执行的线程。

然而,这正是您执行 IO 密集型任务时发生的情况,例如当您从数据库中检索或保存数据或调用下游服务时。

如果对数据库的调用需要几秒钟或更长时间,并且另一个调用进入(即使是另一个方法),则需要从线程池中获取额外的线程。

感谢 .NET 4.5 和 C# 5 中对 asynchronous programming 的支持,为 ASP.NET Web API 服务编写异步方法非常容易。只需将返回类型设置为 Task(如果同步版本返回 void)或 Task,将 T 替换为同步方法的返回类型。然后在方法中,执行一个非阻塞的 IO-bound 异步操作。

将方法标记为异步允许您等待异步操作,编译器将其余方法转换为在另一个线程上执行的延续或回调,通常取自线程池。

阅读关于此Build Async Services with ASP.NET Web API and Entity Framework 6的完整文章

【讨论】:

    猜你喜欢
    • 2017-05-28
    • 1970-01-01
    • 2017-05-19
    • 2016-08-02
    • 1970-01-01
    • 2016-09-16
    • 1970-01-01
    • 2020-11-26
    • 1970-01-01
    相关资源
    最近更新 更多