简体   繁体   English

.NetCore WebAPI方法与EFCore查询是否异步

[英].NetCore WebAPI methods Async or Not with EFCore query

What is considered best(or better) practice to have as default state and why, and what are the real benefits of either? 具有最佳状态的最佳实践是什么?为什么?这两种方法的真正好处是什么?
For example if we have Get method in controller should it be: 例如,如果控制器中有Get方法,则它应为:

public virtual IActionResult Get(int page = 1, int pageSize = 100)
{
    var q = repository.Query().AsNoTracking().ProjectTo<UserViewModel>();
    q = q.Skip((page - 1) * pageSize).Take(pageSize);
    return new OkObjectResult(q);
}

or 要么

public virtual async Task<IActionResult> Get(int page = 1, int pageSize = 100)
{
    var q = repository.Query().AsNoTracking().ProjectTo<UserViewModel>();
    q = q.Skip((page - 1) * pageSize).Take(pageSize);
    return new OkObjectResult(await q.ToListAsync());
}

If async is prefered is this code good for it and enough? 如果首选异步 ,那么此代码是否适合它并且足够了?
Also Query() in repository is simply 同样, 存储库中的 Query()也很简单
public virtual IQueryable<User> Query() { return context.Set<User>().AsQueryable(); }

I have found here that async was in fact slower: https://github.com/aspnet/EntityFramework/issues/5816 我在这里发现异步实际上更慢: https : //github.com/aspnet/EntityFramework/issues/5816
That bug was apparently fixed, but I don't know what are performance comparison in the latest version. 该错误显然已修复,但我不知道最新版本中的性能比较是什么。

The benefits of async/await over regular, synchronized code, is biggest when your server is under heavy enough load that freeing up threads on the thread pool makes a difference. 当服务器承受足够高的负载以释放线程池中的线程时,与常规的同步代码相比, async/await的好处是最大的。 Before then, the overhead of context tracking and switching can easily be bigger than the performance gains of freeing up threads. 在此之前,上下文跟踪和切换的开销很容易大于释放线程的性能收益。

I tend to favor using the asynchronous API over the synchronous, mainly because I've been in a few projects where high load and synchronous code was a high enough problem that someone decided it was time to refactor and move to async , and it was a pain every time. 我倾向于使用异步API而不是使用同步API,主要是因为我参与过一些项目,在这些项目中,高负载和同步代码已经是一个足够高的问题,以至于有人认为是时候重构并转向async ,每次都痛苦。 It's also becoming more and more common to only expose async API:s (for example, the Azure SDK has many async actions which don't have synchronous counterparts), which means that you might have to perform such a re-write later, if you end up using such an API. 仅公开async API的情况也越来越普遍:(例如,Azure SDK具有许多async操作,而没有同步的对应操作),这意味着您可能需要稍后执行这种重写,如果您最终使用了这样的API。

But if performance is the only thing you want to take into account, you need to profile your application under realistic load and see which approach works best. 但是,如果仅考虑性能,则需要在实际负载下分析应用程序,并查看哪种方法最有效。


Addendum: 附录:

It's quite easy to introduce more of the async / await overhead than necessary. 引入不必要的更多async / await开销非常容易。 A good rule-of-thumb I like to use is to think of three types of methods that can return Task or Task<T> , and follow one of these patterns for each, respectively: 我想使用的一个好的经验法则是考虑三种可以返回TaskTask<T> ,并分别遵循以下一种模式:

  • Methods that are actually synchronous (but return Task or Task<T> , eg in order to allow for overloading with asynchronous variants): return with Task.FromResult . 实际上是同步的方法(但返回TaskTask<T> ,例如,以便允许异步变量重载):返回Task.FromResult

     public Task<string> ActuallySynchronousGetter() { return Task.FromResult("foo"); } 
  • Methods that forward to an asynchronous method, but don't do anything else: just return the Task , no need to await it. 可以转发到异步方法但不执行其他任何操作的方法:只需返回Task ,而无需await它。

     // note: no async/await, just Task<T> public Task<string> ForwardingGetter() { return SomeOtherGetter(); // also with return type Task<string> } 
  • Actual asynchronous methods, that both do something asynchronous (usually I/O) and then work with the result of that asynchronous operation: this is the only time you actually need the async and await keywords . 实际的异步方法都执行异步操作(通常是I / O),然后使用该异步操作的结果进行工作: 这是您真正需要asyncawait关键字的唯一时间

     public async Task<string> GetStringAsynchronously() { var str = await SomeOtherGetter(); return str.Replace("foo", "bar"); // note: we need the actual string here } 

Your code seems to fall in the third case - you need the result of .ToListAsync() in order to pass it to the OkObjectResult constructor. 您的代码似乎属于第三种情况-您需要.ToListAsync()的结果才能将其传递给OkObjectResult构造函数。 I would probably have written the entire thing as one statement, but it's mostly a matter of taste: 我可能会把整个内容写成一个陈述,但这主要是出于品味的问题:

var data = await repository.Query()
    .AsNoTracking()
    .ProjectTo<UserViewModel>()
    .Skip((page - 1) * pageSize)
    .Take(pageSize)
    .ToListAsync();
return new OkObjectResult(data);

Stephen Cleary writes a lot and in depth about how async and await works, and how you should (and should not) use it. Stephen Cleary写了很多关于asyncawait如何工作以及如何(不应该)使用它的文章。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM