【发布时间】:2021-01-24 08:42:50
【问题描述】:
我有一个服务对象,它只是针对 Microsoft SQL 数据库之上的 EF Core 存储库执行查询。我正在尝试将这些同步方法转换为 async 版本。这是一种简化方法的示例...
同步版本
public List<Contact> GetContacts()
{
var ret = this.dbContext.Contacts.ToList();
return ret;
}
我已经看到了几种不创建 ASYNC 方法的方法......然后又......我看到了几种不同的方法来说明你应该如何创建异步方法。我在以下两种方法中哪一种被认为是创建异步方法的“正确”或“最佳”方法之间陷入了困境。
异步版本 1
public Task<List<Contact>> GetContactsAsync()
{
return Task.FromResult(this.dbContext.Contacts.ToList());
}
或
异步版本 2
public async Task<List<Contact>> GetContactsAsync()
{
List<Contact> ret = null;
await Task.Run(()=>{
ret = this.dbContext.Contacts.ToList();
});
return ret;
}
如果查询包含多行逻辑,则可能会进一步复杂化。
这是相同的方法,但包含更多细节。如果您看到除了异步主题之外的问题,那么我很乐意在 PM 或其他内容中了解它们,但是对于这个线程,我想专注于等待/异步的东西。
完整的同步代码
public PaginationResult<Contact> GetContacts(PaginationSpec pagingSpec, List<Expression<Func<Models.Contact, bool>>> filter = null)
{
IQueryable<Contact> query = ContactService.GetContactQuery(this.ctx);
if (filter != null && filter.Count > 0)
{
foreach (var item in filter)
{
query = query.Where(item);
}
}
// get the record count
//
var recordcount = query.Count();
// get the pagination
//
var stage = pagingSpec.ApplyPagination<Models.Contact>(query);
// Construct the paged result.
//
var ret = new PaginationResult<Models.Contact>(recordcount, pagingSpec.CurrentPage, pagingSpec.PageSize, stage.ToList());
return ret;
}
我将如何将其包装在适当的语法中以使此方法异步?我可以想到几种方法...
异步版本 1
public Task<PaginationResult<Contact>> GetContactsAsync(PaginationSpec pagingSpec, List<Expression<Func<Models.Contact, bool>>> filter = null)
{
return Task.FromResult(GetContacts(pagingSpec, filter)) // simply call the synchronous method ??;
}
或
异步版本 2
public async Task<PaginationResult<Contact>> GetContactsAsync()
{
PaginationResult<Contact> ret = null;
await Task.Run(()=>{
// Encapsulate the execution code within the RUN method ??
//
IQueryable<Contact> query = ContactService.GetContactQuery(this.ctx);
if (filter != null && filter.Count > 0)
{
foreach (var item in filter)
{
query = query.Where(item);
}
}
// get the record count
//
var recordcount = query.Count();
// Apply the pagination spec to the query
//
var stage = pagingSpec.ApplyPagination<Models.Contact>(query);
// Construct the esult.
//
ret = new PaginationResult<Models.Contact>(recordcount, pagingSpec.CurrentPage, pagingSpec.PageSize, stage.ToList());
});
return ret;
}
其中任何一个都不合适,比一个或另一个更好,还是我错过了第三个选项?
尝试学习这个等待/异步的东西,感谢任何帮助!谢谢!
【问题讨论】:
-
您在这里有 2 个单独的问题,可能还有多个变体。无论如何,当你不是时不要假装是异步的。 blog.stephencleary.com/2013/11/… 如果有异步版本的方法使用它们,不要将它们包装在任务中(即使你没有展示,但只是把它放在那里)。
-
也许,你还没有到提出问题的阶段,请查看 Stephen Clearys 的博客,他是关于任务、异步和等待方面阅读量最大的作者之一,并且经常在这里回答问题 ( 1000 个)
-
Should I expose asynchronous wrappers for synchronous methods? 剧透警告,答案是否定的。顺便说一句,您想通过使用异步方法增强服务的 API 来实现什么?您想提高服务的可扩展性吗?您想提高使用该服务的客户的响应能力吗?还有什么?
-
@TheodorZoulias 我猜这个想法是可能有一个实例可以调用服务方法但不会阻止后续命令的执行。这就是我对 async/await 的理解。但是,如果我已经正确理解了已引用的帖子,则该责任不取决于服务,而是取决于消费者选择使用该方法的方式(?)因此,我将添加到我的应用程序代码中...
await Task.Run(()=>ContactSvcInstance.GetContacts())...而不是?? -
是的,没错。这就是专家的建议。您的服务不应该公开异步方法,除非它们是真正异步的,深入其核心。
标签: c# asynchronous .net-core async-await