EF6 two contexts vs. single context with two awaits

前端 未结 1 1691
长发绾君心
长发绾君心 2020-12-10 23:45

Which of these is a better approach for performance? Note: For some operations I have up to five independent queries to execute.



        
相关标签:
1条回答
  • 2020-12-11 00:09

    As you found out, the DbContext is not thread safe, therefore the only option to really run the queries in parallel would be to create a new DbContext for each Thread/Task.

    The overhead of creating a new DbContext is pretty low. https://msdn.microsoft.com/en-us/library/cc853327.aspx

    Since the object will come from different DbContexts and to further increase performance I recommend you also use NoTracking()

    Edit:

    I made a simple test program with a database I had:

    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 output 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 yes, option 2 is faster...

    0 讨论(0)
提交回复
热议问题