Jes*_*ter 87 c# entity-framework async-await
我正在使用Entity Framework 6处理一些Web API,我的一个控制器方法是"Get All",它希望从我的数据库接收表的内容IQueryable<Entity>.在我的存储库中,我想知道是否有任何有利的理由以异步方式执行此操作,因为我不熟悉使用EF与异步.
基本上归结为
public async Task<IQueryable<URL>> GetAllUrlsAsync()
{
var urls = await context.Urls.ToListAsync();
return urls.AsQueryable();
}
Run Code Online (Sandbox Code Playgroud)
VS
public IQueryable<URL> GetAllUrls()
{
return context.Urls.AsQueryable();
}
Run Code Online (Sandbox Code Playgroud)
异步版本实际上是否会在这里产生性能优势,或者我是通过首先投射到List(使用async mind you)然后转向IQueryable而产生不必要的开销?
Vik*_*ova 203
问题似乎是您误解了async/await如何与Entity Framework一起使用.
那么,让我们来看看这段代码:
public IQueryable<URL> GetAllUrls()
{
return context.Urls.AsQueryable();
}
Run Code Online (Sandbox Code Playgroud)
以及它的使用示例:
repo.GetAllUrls().Where(u => <condition>).Take(10).ToList()
Run Code Online (Sandbox Code Playgroud)
那里发生了什么?
IQueryable对象(尚未访问数据库)repo.GetAllUrls()IQueryable使用指定条件创建一个新对象.Where(u => <condition>IQueryable使用指定的分页限制创建一个新对象.Take(10).ToList().我们的IQueryable对象被编译为sql(like select top 10 * from Urls where <condition>).并且数据库可以使用索引,sql server只向您发送数据库中的10个对象(不是存储在数据库中的所有亿个URL)好的,我们来看看第一个代码:
public async Task<IQueryable<URL>> GetAllUrlsAsync()
{
var urls = await context.Urls.ToListAsync();
return urls.AsQueryable();
}
Run Code Online (Sandbox Code Playgroud)
使用相同的用法示例:
await context.Urls.ToListAsync();.为什么首选使用async/await?我们来看看这段代码:
var stuff1 = repo.GetStuff1ForUser(userId);
var stuff2 = repo.GetStuff2ForUser(userId);
return View(new Model(stuff1, stuff2));
Run Code Online (Sandbox Code Playgroud)
这里发生了什么?
var stuff1 = ...userIdvar stuff2 = ...userId那么让我们看看它的异步版本:
var stuff1Task = repo.GetStuff1ForUserAsync(userId);
var stuff2Task = repo.GetStuff2ForUserAsync(userId);
await Task.WhenAll(stuff1Task, stuff2Task);
return View(new Model(stuff1Task.Result, stuff2Task.Result));
Run Code Online (Sandbox Code Playgroud)
这里发生了什么?
好的代码在这里:
using System.Data.Entity;
public IQueryable<URL> GetAllUrls()
{
return context.Urls.AsQueryable();
}
public async Task<List<URL>> GetAllUrlsByUser(int userId) {
return await GetAllUrls().Where(u => u.User.Id == userId).ToListAsync();
}
Run Code Online (Sandbox Code Playgroud)
注意,using System.Data.Entity为了使用ToListAsync()IQueryable的方法,必须添加.
请注意,如果您不需要过滤和分页,那么您无需使用IQueryable.您可以使用await context.Urls.ToListAsync()和使用物化List<Url>.
您发布的示例与第一个版本存在巨大差异:
var urls = await context.Urls.ToListAsync();
Run Code Online (Sandbox Code Playgroud)
这很糟糕,它基本上是这样select * from table,将所有结果返回到内存中,然后where在内存集合中应用它而不是select * from table where...对数据库进行操作.
在将查询应用于IQueryable(可能通过linq .Where().Select()样式操作,它只返回与查询匹配的db值)之前,第二种方法实际上不会访问数据库.
如果您的示例具有可比性,则async每个请求的版本通常会稍微慢一些,因为编译器生成的状态机中存在更多开销以允许该async功能.
然而,主要的区别(和好处)是async版本允许更多的并发请求,因为它在等待IO完成时不会阻塞处理线程(db查询,文件访问,Web请求等).
| 归档时间: |
|
| 查看次数: |
82452 次 |
| 最近记录: |