SaveChangesAsync没有预期的性能提升

时间:2018-04-06 15:27:56

标签: c# entity-framework asynchronous async-await

我正在比较等待任务的表现,以及一次等待所有任务的时候。我的测试结果:

当循环计数为100时

  • 等待循环 - 11595 ms
  • 等待所有 - 118毫秒

等待所有时间快98倍

循环1000次时

  • 等待循环 - 111249 ms
  • 等待所有 - 189

等一切都快了588倍。

我必须说出我预期的这样的事情。

这是我用于从控制台应用程序进行测试的代码:

   public class TestSaveChanges
        {
            public async Task TestManySaves()
            {
                var loopCount = 100;
                var watch = System.Diagnostics.Stopwatch.StartNew();
                for (int i = 0; i < loopCount; i++)
                {
                    await TestSave();

                }
                watch.Stop();
                Console.WriteLine(watch.ElapsedMilliseconds);

                watch = System.Diagnostics.Stopwatch.StartNew();
                var tasks = new List<Task>();
                for (int i = 0; i < loopCount; i++)
                {
                    tasks.Add(TestSave());

                }
                await Task.WhenAll(tasks);
                watch.Stop();
                Console.WriteLine(watch.ElapsedMilliseconds);
                Console.ReadKey();
            }

            private async Task<bool> TestSave()
            {
                await Task.Delay(100);
                return true;
            }
        }

下一步是测试相同的场景,但真正保存到DB。 我只是用一个新方法替换TestSave方法。

private async Task<bool> TestSave()
{
    using (var db = new BloggingContext())
    {
        var blog = new Blog { Name = Guid.NewGuid().ToString() };
        db.Blogs.Add(blog);
        var res = await db.SaveChangesAsync();
        return res != 0;
    }
}

我没有期望与Task.Delay相同的改进,但我希望看到循环计数的不断改进。

我得到了意想不到的结果。

当循环计数为100时

  • 等待循环 - 9040 ms
  • 等待全部 - 582 ms

快15倍

当循环计数为1000时

  • 等待循环 - 10539 ms
  • 等待全部 - 4042 ms

快了2,6倍

当循环计数为3000时

  • 等待循环 - 18786 ms
  • 等待全部 - 12992毫秒

快了1,4倍

可能循环计数为100 000,它几乎没有更快。 这是为什么?即使循环计数很大,我能以某种方式保持良好的表现吗?

1 个答案:

答案 0 :(得分:0)

您正在尝试比较异步代码和并行代码的性能。异步并不意味着并行。但是,您可以混合使用并行代码和异步代码。

场景1:异步代码

 for (int i = 0; i < loopCount; i++)
 {
    await TestSave();
 }

对于客户端应用程序,异步代码可提高屏幕响应能力。对于服务器端,异步代码有助于实现可伸缩性。例如,在asp.net中,当收到请求时,将选择一个线程池线程来处理该请求。但是,如果请求处理需要访问外部资源(例如从数据库获取某些数据),则只会阻止它执行任何操作。此方案中的异步代码将帮助将该线程返回到池以处理任何进一步的请求,并且一旦外部资源可用,它们将返回以获取它们离开先前请求的位置。因此,服务器能够处理更多请求,然后处理可用的线程池数量。

场景2:并行代码

  var tasks = new List<Task>();
                for (int i = 0; i < loopCount; i++)
                {
                    tasks.Add(TestSave());

                }
  Task.WhenAll(tasks);

  or using Paralle.Foreach

在这种情况下,TestSave将在多个线程上并行执行,从而提高性能。