EF6 two contexts vs. single context with two awaits

c# entity-framework entity-framework-6 performance

Accepted Answer

The only way to truly run the queries in parallel would be to build a new DbContext for each Thread/Task because, as you discovered, the DbContext is not thread safe.

A new DbContext can be created with relatively little overhead. https://msdn.microsoft.com/en-us/library/cc853327.aspx

I advise using NoTracking as well because the item will come from several DbContexts and to improve efficiency even more ()

Edit:

With a database I had, I created a straightforward test program:

class Program
{
    public static void Main(string[] args)
    {
        Console.WriteLine("Warming up db context...");

        using (var db = new TestDbContext())
        {
            Console.WriteLine(db.AuditLogItems.ToList().Count);
        }

        // 1st run
        RunAsync();
        RunTasked();

        // 2nd run
        RunAsync();
        RunTasked();

        Console.ReadKey();
    }

    private static void RunAsync()
    {
        Task.Run(async () =>
        {
            var sw = Stopwatch.StartNew();
            List<AuditLogItem> list1;
            List<AuditLogItem> list2;

            using (var db = new TestDbContext())
            {
                list1 = await db.AuditLogItems.AsNoTracking().ToListAsync();
                list2 = await db.AuditLogItems.AsNoTracking().ToListAsync();
            }

            sw.Stop();
            Console.WriteLine("Executed {0} in {1}ms. | {2}", "Async", sw.ElapsedMilliseconds, list1.Count + " " + list2.Count);

        }).Wait();
    }

    private static void RunTasked()
    {
        Func<List<AuditLogItem>> runQuery = () =>
        {
            using (var db = new TestDbContext())
            {
                return db.AuditLogItems.AsNoTracking().ToList();
            }
        };

        var sw = Stopwatch.StartNew();
        var task1 = Task.Run(runQuery);
        var task2 = Task.Run(runQuery);

        Task.WaitAll(task1, task2);

        sw.Stop();
        Console.WriteLine("Executed {0} in {1}ms. | {2}", "Tasked", sw.ElapsedMilliseconds, task1.Result.Count + " " + task2.Result.Count);
    }
}

The result is:

Warming up db context...
5908
Executed Async in 293ms. | 5908 5908
Executed Tasked in 56ms. | 5908 5908
Executed Async in 194ms. | 5908 5908
Executed Tasked in 32ms. | 5908 5908

So certainly, choice 2 is quicker.

2
3/16/2016 2:01:38 PM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow