第一种方法可以基于该方法Task.Run作业运行在线程池之上,并返回一个任务对象,它代表了这项工作 。这样,方法可以在线程池的不同线程上同时运行:
public IActionResult Get
{
var areas = Task.Run( = > this.GetAreas);
var companies = Task.Run( = > this.GetCompanies);
var resources = Task.Run( = > this.GetResources);
Task.WhenAll(areas, companies, resources);
return Ok(new { areas = areas.Result, companies = companies.Result, resources = resources.Result });
}
Task的Result属性包含详细说明的结果 。方法WhenAll允许暂停当前线程执行,直到所有Task完成 。运行代码,我们可以注意到一个有趣的事情:调用中断,并启动以下异常:
AggregateException:发生一个或多个错误 。(在上一个操作完成之前,第二个操作在此上下文上开始 。这通常是由使用相同DbContext实例的不同线程引起的 。有关如何避免DbContext线程问题的更多信息,请参见
https://go.microsoft.com/fwlink/?linkid=2097913 。[1])
此错误消息告诉我们,方法在不同的线程上同时执行,但是由于它们使用与DbContext相同的实例来连接数据库, 因此引发了异常,DbContext类无法确保线程安全的功能:我们可以轻松地绕过此问题,避免了.NET Core 的依赖注入引擎创建单个实例,而我们为每种方法创建了单独的实例 。作为示例,让我们看看方法GetAreas会如何变化:
public class DataController : ControllerBase
{
private readonly DbContextOptionsBuilder <AppDbContext> optionsBuilder = ;
public DataController(IConfiguration configuration)
{
this.optionsBuilder = new DbContextOptionsBuilder <AppDbContext>
.UseSqlite(configuration.GetConnectionString("DefaultConnection"));
}
[Route("areas")]
public Area GetAreas
{
using(var db = new AppDbContext(this.optionsBuilder.Options))
{
return db.Areas.ToArray;
}
}
}
好吧,现在可以了 。我们应该注意,EFCore提供了一些方法,例如,与方法ToArrayAsync一样,使用相同的DbContext进行异步调用,该方法从IQueryable 创建一个数组,该数组 异步枚举它 。此方法返回Task ,它是表示异步操作的活动 。
这样,我们不再需要使用Task.Run:
public IActionResult Get
{
var areas = this.GetAreas;
var companies = this.GetCompanies;
var resources = this.GetResources;
Task.WhenAll(areas, companies, resources);
return Ok(new { areas = areas.Result, companies = companies.Result, resources = resources.Result });
}
[Route("areas")]
public Task<Area> GetAreas
{
return db.Areas.ToArrayAsync;
}
无论如何,Microsoft不能保证这些异步方法在每种情况下都能工作,因为DbContext尚未设计为线程安全的 。您可以查询此链接以获取更多信息:https :
//docs.microsoft.com/zh-cn/ef/core/querying/async
使用Entity Framework Core时,最佳实践是在启动另一个异步操作之前,为每个异步操作都拥有一个DbContext或等待每个异步操作完成 。当我们必须进行异步调用并返回结果时,这种最佳做法是可以的 。
但是,如果我们想在返回结果之前对结果进行一些操作,会发生什么?如果我们想向列表中添加元素怎么办?我们应该等待结果,添加元素,然后返回修改后的列表:
[Route("companies")]
public Task<Company> GetCompanies
{
using (var db = new AppDbContext(this.optionsBuilder.Options))
{
var data = https://www.isolves.com/it/cxkf/bk/2021-12-01/this.db.Companies.ToListAsync.Result;
data.Insert(0, new Company { Id = 0, Name = "-"});
return data.ToArray;
}
}
不幸的是,该代码无法编译,因为data.ToArray返回的是数组而不是Task 。实际上,这里我们需要三个线程:主调用方(Get),数据库查询(
this.db.Companies.ToListAsync)和一个线程,该线程将一个值添加到列表中 。我们有三种方法可以做到这一点:让我们用三种单一方法来查看它们 。我们已经看到的第一个,可以使用Task.Run方法:
[Route("companies")]
public Task<Company> GetCompanies
{
return Task.Run( =>
{
using (var db = new AppDbContext(this.optionsBuilder.Options))
推荐阅读
- 一文看懂“超融合”和“虚拟化”的区别
- 爷青回!经典老牌音乐播放器Winamp宣布回归
- IOS技术分享|WebRTC iOS源码下载&编译
- 一张图看懂私域流量的底层逻辑
- 详解Python软件安装教程和配置,小白都能看懂的教程,值得收藏
- 一文告诉你USB4和雷雳4到底是什么
- 百度SEO搜索引擎优化为什么会提倡"白帽"拒绝"黑帽"
- 看懂IPv6+,这篇就够了
- 不要让爱你的觉得不值?我的爱对你来说一文不值
- 微信朋友圈使用"提醒谁看"时,别人能看到吗?