如何更快地运行此entity framework示例

我有这个代码用于向数据库添加大约1500条记录:

async void button7_Click(object sender, EventArgs e) { var task = await Task.Run(() => { Random rnd = new Random(); for (int i = 0; i <= 1500; i++) { db.Tbls.Add(new Tbl() { Name = "User" + i + 1, Num = rnd.Next(10, i + 10) / 10 }); progress.Report(i * 100 / 1500); } db.SaveChanges(); return db.Tbls.Count(); }); } 

但是完成这个过程花了大约4秒钟,但因为我使用async/await它不会冻结UI。 现在我的问题是:如何改进此代码以更快地运行。 我如何在这里使用并行编程? 你能告诉我一个如何使用TPL的例子吗?

编辑

我按照建议使用了并行循环和AddRange ,但没有效果。 在所有建议的方式,我的过程仍然需要大约4秒。 如果有人能帮助我解决这个问题,我真的很感激。

如果性能是目标,那么你应该使用EF以外的东西,比如dapper (StackOverflow.com使用的东西)或原始ADO.Net 。 除此之外,您可以通过在保存时禁用更改自动检测和validation来提高entity framework性能:

 yourDbContext.Configuration.AutoDetectChangesEnabled = false; yourDbContext.Configuration.ValidateOnSaveEnabled = false; 

您应该将上面的代码与使用AddRange @Evk建议结合起来。

另一种可能有助于加速插入的解决方案是使用BulkInsert (从这里拍摄的图像):

在此处输入图像描述

并行处理在这里不会有很大的帮助,因为你的循环本身就没有时间。 所有消耗的时间都分为两个方面:

  1. 当您向Entity Framework上下文添加新项目(并且您在此处使用EF)时,它会对上下文中的许多项目执行某些操作(而不仅仅是您添加的项目),并且您添加的项目越多越慢。

  2. Perfoming 1500数据库插入也需要一些时间。

这里最简单的方法是减少上面列表中第1点所花费的时间。 你可以这样做:

 async void button7_Click(object sender, EventArgs e) { var task = await Task.Run(() => { Random rnd = new Random(); var tbls = new List(); for (int i = 0; i <= 1500; i++) { tbls.Add(new Tbl() { Name = "User" + i + 1, Num = rnd.Next(10, i + 10) / 10 }); progress.Report(i * 100 / 1500); } db.Tbls.AddRange(tbls); db.SaveChanges(); return db.Tbls.Count(); }); } 

通过使用AddRange并首先收集简单List所有项目,您将大大减少代码消耗的时间至少低于1秒。

更新。 如果你想使用并行循环,即使这没有帮助,你可以这样做:

 int seed = Environment.TickCount; var random = new ThreadLocal(() => new Random(Interlocked.Increment(ref seed))); var tbls = new ConcurrentBag(); Parallel.For(0, 1500, (i) => { tbls.Add(new Tbl() { Name = "User" + i + 1, Num = random.Value.Next(10, i + 10) / 10 }); }); db.Tbls.AddRange(tbls); 

注意事项:

  • Random不是线程安全的,所以我们使用线程局部实例(一个用于并行循环内的每个线程),每个实例具有不同的种子值。
  • List不是线程安全的 - 我们使用ConcurrentBag代替。