Gar*_*rom 0 c# asynchronous async-await .net-core
我有一个服务对象,它只是对 Microsoft SQL 数据库之上的 EF Core 存储库执行查询。我正在尝试将这些同步方法转换为异步版本。这是一种简化方法的示例......
同步版本
public List<Contact> GetContacts()
{
var ret = this.dbContext.Contacts.ToList();
return ret;
}
Run Code Online (Sandbox Code Playgroud)
我已经看到了几种不创建异步方法的方法......再说一遍......我已经看到了几种不同的方法来说明你应该如何创建异步方法。我陷入了以下两种方法中的哪一种被认为是创建异步方法的“正确”或“最佳”方式之间。
异步版本 1
public Task<List<Contact>> GetContactsAsync()
{
return Task.FromResult(this.dbContext.Contacts.ToList());
}
Run Code Online (Sandbox Code Playgroud)
或者
异步版本 2
public async Task<List<Contact>> GetContactsAsync()
{
List<Contact> ret = null;
await Task.Run(()=>{
ret = this.dbContext.Contacts.ToList();
});
return ret;
}
Run Code Online (Sandbox Code Playgroud)
如果查询包含多行逻辑,则可能会使情况进一步复杂化。
这是包含更多细节的相同方法。如果您看到异步主题之外的问题,那么我很乐意在 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;
}
Run Code Online (Sandbox Code Playgroud)
我将如何用适当的语法包装它以使此方法异步?我可以想到几种方法......
异步版本 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 ??;
}
Run Code Online (Sandbox Code Playgroud)
或者
异步版本 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;
}
Run Code Online (Sandbox Code Playgroud)
这些中的任何一个都不合适,比一个更好,还是我错过了第三个选项?
尝试学习这个等待/异步的东西,任何帮助表示赞赏!谢谢!
这两者通常都被认为是不正确的。
异步版本 1
这个的问题在于它实际上不是异步的。它只是在做同样的同步工作并将它包装在一个Task<T>.
异步版本 2
这个问题是从调用者的角度来看它是异步的,但在它的实现中是同步的。它只是Task.Run用于在线程池线程上运行同步代码,因此它看起来是异步的。这就是我所说的“假异步”,这对于桌面应用程序来说是可以的(不理想),当然不推荐用于 ASP.NET 应用程序。
更合适的解决方案如下所示:
public async Task<List<Contact>> GetContactsAsync()
{
return await this.dbContext.Contacts.ToListAsync();
}
Run Code Online (Sandbox Code Playgroud)
这是假设您有ToListAsync可用的方法。请注意与同步版本的相似之处:
public List<Contact> GetContacts()
{
return this.dbContext.Contacts.ToList();
}
Run Code Online (Sandbox Code Playgroud)
一般来说,你要从最底层开始,即实际执行IQueryable. 在这种情况下,我假设那是ToList,但如果ToList是您自己的方法,那么它可能是该方法调用的任何内容。一旦你找到了最低级别的代码,然后更改是在使用await,并让异步从那里成长。
| 归档时间: |
|
| 查看次数: |
130 次 |
| 最近记录: |