的ASP.NET Web API 2异步操作方法与Task.Run性能 [英] ASP.NET Web API 2 Async action methods with Task.Run performance

查看:1294
本文介绍了的ASP.NET Web API 2异步操作方法与Task.Run性能的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图基准(使用Apache工作台)一对夫妇的ASP.NET Web API 2.0端点。其中之一是同步的,一个异步。

I'm trying to benchmark (using Apache bench) a couple of ASP.NET Web API 2.0 endpoints. One of which is synchronous and one async.

        [Route("user/{userId}/feeds")]
        [HttpGet]
        public IEnumerable<NewsFeedItem> GetNewsFeedItemsForUser(string userId)
        {
            return _newsFeedService.GetNewsFeedItemsForUser(userId);
        }

        [Route("user/{userId}/feeds/async")]
        [HttpGet]
        public async Task<IEnumerable<NewsFeedItem>> GetNewsFeedItemsForUserAsync(string userId)
        {
            return await Task.Run(() => _newsFeedService.GetNewsFeedItemsForUser(userId));
        }

桑德森presentation 我发出以下命令后 AB -n 100 -c 10的http://本地主机.... 到每个端点。

After watching Steve Sanderson's presentation I issued the following command ab -n 100 -c 10 http://localhost.... to each endpoint.

我很惊讶作为每个端点基准似乎是大致相同。

I was surprised as the benchmarks for each endpoint seemed to be approximately the same.

去了什么史蒂夫解释我期待的异步终端将是更好的性能,因为它会释放线程池中的线程回立即线程池,从而使它们可用于其他请求和提高吞吐量。但数字似乎完全相同。

Going off what Steve explained I was expecting that the async endpoint would be more performant because it would release thread pool threads back to the thread pool immediately, thus making them available for other requests and improving throughput. But the numbers seem exactly the same.

我是什么误解吗?

推荐答案

使用等待Task.Run 以创建异步的WebAPI是坏主意 - 你将仍然使用一个线程,甚至可以从用于申请相同的线程池

Using await Task.Run to create "async" WebApi is a bad idea - you will still use a thread, and even from the same thread pool used for requests.

这将导致在这个博客<良好的细节描述了一些不愉快的时刻/ A>

It will lead to some unpleasant moments described in good details at this blog:


      
  • 额外的(不必要的)线程切换到Task.Run线程池中的线程。同样地,当该线程完成的请求,它必须
      输入请求上下文(这是不实际的线程切换,但
      确实有开销)。

  •   
  • 额外的(不必要的)的垃圾被创建。异步编程是一个折衷:你得到更高的费用增长响应
      内存使用情况。在这种情况下,你最终会创造更多的垃圾
      异步操作是完全不必要的。

  •   
  • 的ASP.NET线程池启发式由Task.Run意外借线程池线程揭去。我没有很多
      体验这里,但我的直觉告诉我,启发式
      要恢复的不错,如果意想不到的任务是很短,并会
      如果意外任务持续超过两个不处理它作为优雅
      秒。

  •   
  • ASP.NET是不能够提前终止的请求,即,如果客户端断开或者请求超时。在同步的情况下,
      ASP.NET知道请求线程,​​并可能终止它。在里面
      异步情况下,ASP.NET并不知道辅助线程池
      线程是供的请求。这可以通过使用来解决这个问题
      取消标记,但是这是这个博客帖子的范围。

  •   

基本上,你不要让任何异步到ASP.NET - 你只是隐藏异步门面背后的CPU绑定同步code。 异步对自己是理想的I /​​ O绑定code,因为它允许在其最高效率地利用CPU(线程)(无阻塞的I / O) ,但是当你有计算密集型code,你仍然有能力利用CPU到相同的程度。

Basically, you do not allow any asynchrony to the ASP.NET - you just hide the CPU-bound synchronous code behind the async facade. Async on its own is ideal for I/O bound code, because it allows to utilize CPU (threads) at their top efficiency (no blocking for I/O), but when you have Compute-bound code, you will still have to utilize CPU to the same extent.

和考虑到额外的开销从工作和上下文切换,你会得到甚至沃瑟效果比简单的同步控制器的方法。

And taking into account the additional overhead from Task and context switching you will get even worser results than with simple sync controller methods.

如何使之真正异步:

GetNewsFeedItemsForUser 方法要变为异步

    [Route("user/{userId}/feeds/async")]
    [HttpGet]
    public async Task<IEnumerable<NewsFeedItem>> GetNewsFeedItemsForUserAsync(string userId)
    {
        return await _newsFeedService.GetNewsFeedItemsForUser(userId);
    }

要做到这一点:


  • 如果有那么一些图书馆法寻找它的异步变体(如果有没有 - 运气不好,你就必须寻找一些竞争模拟)。

  • 如果是使用文件系统或数据库,然后利用他们的异步设备以创建方法异步API您的自定义方法。

  • If it is some library method then look for its async variant (if there are none - bad luck, you'll have to search for some competing analogue).
  • If it is your custom method using file system or database then leverage their async facilities to create async API for the method.

这篇关于的ASP.NET Web API 2异步操作方法与Task.Run性能的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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