.NetCore WebAPI方法与EFCore查询异步或不同步

时间:2017-07-04 11:30:15

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

什么被认为是最佳(或更好)的做法,具有默认状态和原因,以及它们的真正好处是什么?
例如,如果我们在控制器中有 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 ,这段代码是否适合它并且足够了?
存储库中的 Query()也只是为了 public virtual IQueryable<User> Query() { return context.Set<User>().AsQueryable(); }

我在这里发现 async 实际上更慢了: https://github.com/aspnet/EntityFramework/issues/5816
该错误显然是固定的,但我不知道最新版本中的性能比较是什么。

1 个答案:

答案 0 :(得分:3)

async/await优于常规同步代码的好处,当您的服务器负载足够大以至于释放线程池上的线程有所不同时,这是最大的。在此之前,上下文跟踪和切换的开销很容易大于释放线程的性能提升。

我倾向于使用异步API而不是同步,主要是因为我已经进入了一些项目,其中高负载和同步代码是一个足够高的问题,有人认为是时候重构并转移到{{1每次都是痛苦的。仅公开async API会变得越来越普遍(例如,Azure SDK有许多async个动作没有同步对应物),这意味着您可能如果您最终使用这样的API,则稍后执行此类重写。

但如果您想要考虑性能,那么您需要在实际负载下分析您的应用程序,并了解哪种方法效果最佳。

附录:

引入更多async / async开销非常容易。我喜欢使用的一个很好的经验法则是考虑可以返回awaitTask的三种类型的方法,并分别遵循以下模式中的一种:

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

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

    await
  • 实际的异步方法,它们都执行异步操作(通常是I / O),然后使用该异步操作的结果:这是您实际需要// note: no async/await, just Task<T> public Task<string> ForwardingGetter() { return SomeOtherGetter(); // also with return type Task<string> } 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

Stephen Cleary详尽而深入地介绍了var data = await repository.Query() .AsNoTracking() .ProjectTo<UserViewModel>() .Skip((page - 1) * pageSize) .Take(pageSize) .ToListAsync(); return new OkObjectResult(data); async如何运作,以及您应该(而且不应该)如何使用它。