C# .NetCore WebAPI方法是否与EFCore查询异步
默认状态下的最佳(或更好)实践是什么?为什么?两者的真正好处是什么?C# .NetCore WebAPI方法是否与EFCore查询异步,c#,asynchronous,asp.net-core,async-await,entity-framework-core,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).Tak
例如,如果我们在控制器中有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);
}
公共虚拟IActionResult Get(int page=1,int pageSize=100)
{
var q=repository.Query().AsNoTracking().ProjectTo();
q=q.Skip((第1页)*页面大小)。Take(页面大小);
返回新的OkObjectResult(q);
}
或
公共虚拟异步任务Get(int page=1,int pageSize=100)
{
var q=repository.Query().AsNoTracking().ProjectTo();
q=q.Skip((第1页)*页面大小)。Take(页面大小);
返回新的OkObjectResult(等待q.ToListSync());
}
如果首选async,那么该代码是否适合它并且足够了?存储库中的Query()也是简单的
公共虚拟IQueryable查询(){return context.Set().AsQueryable();}
我在这里发现,async实际上速度较慢:
该错误显然已修复,但我不知道最新版本中的性能比较是什么。与常规同步代码相比,
async/await
的好处最大,因为当服务器负载足够大时,释放线程池上的线程会产生不同。在此之前,上下文跟踪和切换的开销很容易大于释放线程的性能增益
我倾向于使用异步API而不是同步API,主要是因为我参与过一些项目,在这些项目中,高负载和同步代码是一个非常严重的问题,以至于有人认为是时候重构并转向async
,而且每次都很痛苦。仅公开async
API:s也变得越来越普遍(例如,Azure SDK有许多async
操作没有同步对应项),这意味着如果您最终使用这样的API,您可能必须在以后执行这样的重写
但是,如果性能是唯一需要考虑的因素,那么您需要在实际负载下分析应用程序,并查看哪种方法最有效
增编: 引入更多的
异步
/等待
开销比必要的开销要容易得多。我喜欢使用的一条经验法则是,考虑三种类型的方法,它们可以返回Task
或Task
,并分别遵循以下模式之一:
- 实际同步的方法(但返回
或任务
,例如为了允许异步变量重载):返回任务
任务。FromResult
public Task<string> ActuallySynchronousGetter() { return Task.FromResult("foo"); }
- 实际的异步方法,既执行异步操作(通常是I/O),又处理异步操作的结果:这是您实际需要
和async
关键字的唯一时间wait
详细介绍了
和async
的工作原理,以及您应该(和不应该)如何使用它。与常规同步代码相比,await
的好处最大,因为当您的服务器负载足够重时,释放线程池中的线程会有所不同。在此之前,上下文跟踪和切换的开销很容易大于释放线程的性能增益 我倾向于使用异步API而不是同步API,主要是因为我参与过一些项目,在这些项目中,高负载和同步代码是一个非常严重的问题,以至于有人认为是时候重构并转向async/await
,而且每次都很痛苦。仅公开async
API:s也变得越来越普遍(例如,Azure SDK有许多async
操作没有同步对应项),这意味着如果您最终使用这样的API,您可能必须在以后执行这样的重写 但是,如果性能是唯一需要考虑的因素,那么您需要在实际负载下分析应用程序,并查看哪种方法最有效async
增编: 引入更多的
/异步
开销比必要的开销要容易得多。我喜欢使用的一条经验法则是,考虑三种类型的方法,它们可以返回等待
或Task
,并分别遵循以下模式之一:Task
- 实际同步的方法(但返回
或任务
,例如为了允许异步变量重载):返回任务
任务。FromResult
public Task<string> ActuallySynchronousGetter() { return Task.FromResult("foo"); }
- 实际的异步方法,既执行异步操作(通常是I/O),又处理异步操作的结果:这是您实际需要
和async
关键字的唯一时间wait
详细介绍了
和async
的工作原理,以及您应该(和不应该)如何使用它。第一个线程将阻止请求线程,因此在高负载/流量情况下,一旦所有线程用完,它将很快开始向调用者返回http 500错误。请注意,以后使用正确的标签!第一个线程将阻塞请求线程,因此在高负载/流量场景中,当所有线程用完后,它将很快开始向调用者返回http 500错误。请注意,以后使用正确的标签!那么第二个示例中的代码是否可以,特别是async Wait代码是否只能在控制器中按原样离开存储库?@borisdj请参阅我的更新答案以了解更多指导原则。就像您的代码一样。由于repository.Query(),第三种情况下失败了,如果是这样,那么该方法应该是什么样子?我认为您当前对await
的实现很好。现在我有点困惑了,到底是什么问题repository.Query()
// note: no async/await, just Task<T> public Task<string> ForwardingGetter() { return SomeOtherGetter(); // also with return type Task<string> }
public async Task<string> GetStringAsynchronously() { var str = await SomeOtherGetter(); return str.Replace("foo", "bar"); // note: we need the actual string here }
var data = await repository.Query() .AsNoTracking() .ProjectTo<UserViewModel>() .Skip((page - 1) * pageSize) .Take(pageSize) .ToListAsync(); return new OkObjectResult(data);
- 实际同步的方法(但返回