c# - .Net Core Web API 方法是否与 EF Core 查询异步

标签 c# asynchronous asp.net-core async-await entity-framework-core

什么被认为是默认状态的最佳(或更好)实践,为什么,以及两者的真正好处是什么?
例如,如果我们在 Controller 中有 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);
}

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());
}

如果首选async,这段代码是否适合它?
Repository 中的 Query() 也很简单
public virtual IQueryable<User> Query() { return context.Set<User>().AsQueryable(); }

我在这里发现 async 实际上更慢: https://github.com/aspnet/EntityFramework/issues/5816
那个bug貌似修复了,但是不知道最新版本的性能对比如何。

最佳答案

async/await 的好处当您的服务器承受足够大的负载以至于释放线程池中的线程会产生影响时,常规的同步代码是最大的。在此之前,上下文跟踪和切换的开销很容易大于释放线程带来的性能提升。

我倾向于使用异步 API 而不是同步,主要是因为我参与过一些项目,其中高负载和同步代码是一个足够高的问题,以至于有人决定是时候重构并转移到 async 了。 ,每次都很痛苦。只公开 async 也变得越来越普遍API:s(例如,Azure SDK 有许多没有同步对应项的 async 操作),这意味着您可能必须稍后执行这样的重写,如果您结束开始使用这样的 API。

但如果性能是您唯一要考虑的因素,您需要在实际负载下分析您的应用程序,看看哪种方法最有效。


附录:

很容易介绍更多 async/await不必要的开销。我喜欢使用的一个很好的经验法则是考虑三种可以返回 Task 的方法。或 Task<T> , 并分别遵循以下模式之一:

  • 实际上是同步的方法(但返回 TaskTask<T> ,例如为了允许使用异步变量重载):返回 Task.FromResult .

    public Task<string> ActuallySynchronousGetter()
    {
        return Task.FromResult("foo");
    }
    
  • 转发给异步方法但不做任何其他事情的方法:只返回 Task , 不需要 await

    // note: no async/await, just Task<T>
    public Task<string> ForwardingGetter()
    {
         return SomeOtherGetter(); // also with return type Task<string>
    }
    
  • 实际的异步方法,它们都执行一些异步操作(通常是 I/O),然后使用该异步操作的结果:这是您真正需要 async 的唯一时间和 await关键词

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

您的代码似乎属于第三种情况 - 您需要 .ToListAsync() 的结果为了将它传递给 OkObjectResult构造函数。我可能会把整个事情写成一个声明,但这主要是一个品味问题:

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

Stephen Cleary关于如何 async 写了很多深入的文章和 await工作原理,以及您应该(和不应该)使用它的方式。

关于c# - .Net Core Web API 方法是否与 EF Core 查询异步,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44904803/

相关文章:

c# - 在 TabControl 中查找控件

c# - 为什么 .NET Core 的模型验证器在验证消息上显示模型属性的名称而不是 JSON 字段名称?

asp.net-mvc - 如何在 Web API ASP.Net core 中对异常过滤器进行单元测试。不想模拟 onException 方法

asp.net-core - IWebHost WebHostBuilder BuildWebHost和有什么不一样

c# - 如何将 Func<T> 用作注入(inject)属性

c# - 将多个 UserControl 附加到 WinForm 面板

java - 如何在 Android java 插件端等待异步操作(任何 I/O)?

C非阻塞键盘输入

c# - DataTable 列值分组和排序