C# 使用ASP.NET异步/等待进行线程管理
我有一个数据库实体类型C# 使用ASP.NET异步/等待进行线程管理,c#,multithreading,entity-framework,asynchronous,async-await,C#,Multithreading,Entity Framework,Asynchronous,Async Await,我有一个数据库实体类型entity,一长串东西和方法 private Task<Entity> MakeEntity(Thingy thingy) { ... } 私有任务生成实体(Thingy Thingy){ ... } MakeEntity做很多事情,并且是CPU限制的。我想将我所有的东西转换成实体,并将它们保存在db.context中。考虑到 我不想尽快完成 实体的数量很大,我想有效地使用数据库,所以我想开始保存更改并等待远程数据库完成它的工作 我如何才能做到这一
entity
,一长串东西和方法
private Task<Entity> MakeEntity(Thingy thingy) {
...
}
私有任务生成实体(Thingy Thingy){
...
}
MakeEntity做很多事情,并且是CPU限制的。我想将我所有的东西转换成实体,并将它们保存在db.context中。考虑到
- 我不想尽快完成
- 实体的数量很大,我想有效地使用数据库,所以我想开始保存更改并等待远程数据库完成它的工作
我如何才能做到这一点?我真正想要的是在等待数据库完成它的工作时循环,并提供到目前为止所有新创建的实体,直到数据库处理完它们为止。去那里最好的路线是什么?如果同时调用,我会遇到saveChanges,所以我不能这样做。我真正想要的是有一个由八个线程组成的线程池(或者更确切地说,有多少个线程就有多少个线程)来执行CPU绑定的工作,一个线程执行SaveChanges()
您可以设置一个由N个CPU工作线程组成的管道,将其送入数据库工作线程。数据库工作人员可以对项目进行批处理
由于MakeEntity
受CPU限制,因此不需要在那里使用async
和wait
<代码>等待
不会创建任务或线程(一种常见的误解)
您需要提供一个从IEnumerable
创建批的方法。这可以在网上找到
如果数据库部分不需要批处理,可以删除该代码
对于数据库部分,可能是因为它似乎是一个低频操作。这是一种“异步流”,这总是有点尴尬
在这种情况下(假设您确实希望在ASP.NET上使用多线程,一般不推荐使用多线程),我认为这是您最好的选择。您可以将TransformBlock
与一起使用,并将其链接到执行SaveChanges
操作的ActionBlock
请记住,对CPU绑定的代码使用同步签名(而不是
async
/await
),对I/O绑定的代码使用异步方法(即savechangesync
)。您确定要在ASP.NET上使用多线程吗?请记住,当单个请求使用多个线程时,这将显著影响您的可伸缩性,因为这些线程不能用于其他请求。您是否对每个Thingy
实例重复调用MakeEntity
?此外,是否无法批处理一堆Thingy
的CPU限制处理,并将生成的实体
附加到上下文中,然后只为一个DB往返调用SaveChanges
?@Asad MakeEntity应该为每件事情调用,是吗(但这实际上是我问题的一部分。为整个批次调用一次SaveChanges将是最好的,但由于所需的工作量不可行。我要避免的主要事情是独立工作MakeEntity
,并等待SaveChanges
的中间结果,同时注意由于EF不支持多个“正在运行”的SaveChanges。
var thingies = ...;
var entities = thingies.AsParallel().WithDOP(8).Select(MakeEntity);
var batches = CreateBatches(entities, batchSize: 100);
foreach (var batch in batches) {
Insert(batch);
}