How can I run this entity framework sample faster

我只是一个虾纸丫 提交于 2019-12-18 18:25:35

问题


I have this code for adding about 1500 record to database:

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();

    });
}

But it took about 4 second to complete the process but because I used async/await it doesn't freezes the UI. Now my question is: how can I improve this code to run faster. How can I use parallel programming here? Can you show me an example of how use TPL?

EDIT:

I used parallel loop and AddRange as suggested but it has no effect. In all suggested ways my process still take about 4 seconds. I really appreciate if someone can help me to solve this issue.


回答1:


If performance is the goal then you should use something other than EF like dapper (same thing StackOverflow.com is using) or raw ADO.Net. Other than that you could improve the Entity Framework performance by disabling change auto detection and validation on save:

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

You should combine the above code with @Evk advice of using AddRange.

Another solution that might help speedup your inserts is by using BulkInsert (image taken from here):




回答2:


Parallel processing won't be of big help here, because your loop by itself takes no time at all. All consumed time goes into two things:

  1. When you add new item to Entity Framework context (and you use EF here as I understand) - it performs some operations on many items in the context (not just the item you added) and it goes slower and slower the more items you added.

  2. Perfoming 1500 database inserts also takes some time.

The easiest thing to do here is to reduce time taken by point 1 in the list above. You can do it like this:

async void button7_Click(object sender, EventArgs e)
{
    var task = await Task.Run(() =>
    {
        Random rnd = new Random();
        var tbls = new List<Tbl>();
        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();

    });
}

By using AddRange and first collecting all items in simple List you will greately reduce time consumed by your code to at least below 1 second.

Update. If you want to use parallel loop, even if that won't help, you can do it like this:

int seed = Environment.TickCount;
var random = new ThreadLocal<Random>(() => new Random(Interlocked.Increment(ref seed)));
var tbls = new ConcurrentBag<Tbl>();
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);

Things to note:

  • Random is not thread safe so we use thread local instances (one for each thread inside parallel loop), each one with different seed value.
  • List is not thread safe - we use ConcurrentBag instead.


来源:https://stackoverflow.com/questions/37374480/how-can-i-run-this-entity-framework-sample-faster

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!