C# SaveChangesSync没有预期的性能改进
我在一个接一个地等待任务和同时等待所有任务时比较性能。我的测试结果: 循环计数为100时C# SaveChangesSync没有预期的性能改进,c#,entity-framework,asynchronous,async-await,C#,Entity Framework,Asynchronous,Async Await,我在一个接一个地等待任务和同时等待所有任务时比较性能。我的测试结果: 循环计数为100时 在循环中等待-11595毫秒 等待所有时间-118毫秒 等一切都快98倍的时候 当循环1000次时 在循环中等待-111249毫秒 等待一切的到来——189 等一切都快588倍的时候 我必须说,像这样的事情我早就预料到了 这是我用于从控制台应用程序进行测试的代码: public class TestSaveChanges { public async T
- 在循环中等待-11595毫秒
- 等待所有时间-118毫秒
- 在循环中等待-111249毫秒
- 等待一切的到来——189
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;
}
}
公共类TestSaveChanges
{
公共异步任务TestManySaves()
{
var循环计数=100;
var watch=System.Diagnostics.Stopwatch.StartNew();
for(int i=0;i
下一步是测试相同的场景,但实际保存到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;
}
}
private异步任务TestSave()
{
使用(var db=new BloggingContext())
{
var blog=newblog{Name=Guid.NewGuid().ToString()};
添加(blog);
var res=await db.SaveChangesAsync();
返回res!=0;
}
}
我并没有期望Task.Delay会有同样的改进,但我希望看到循环计数会有更大的改进
我得到了意想不到的结果
循环计数为100时
- 在循环中等待-9040毫秒
- 等待所有时间-582毫秒
- 在循环中等待-10539毫秒
- 等待所有时间-4042毫秒
- 在循环中等待-18786毫秒
- 等待所有时间-12992毫秒
为什么会这样?即使循环计数很大,我也能保持良好的性能吗?您正在尝试比较异步代码和并行代码的性能。异步并不意味着并行。但是,您可以混合使用并行代码和异步代码 场景1:异步代码
for (int i = 0; i < loopCount; i++)
{
await TestSave();
}
for(int i=0;i
对于客户端应用程序,异步代码提高了屏幕响应能力。对于服务器端,异步代码有助于提高可伸缩性。例如,在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
var tasks=newlist();
for(int i=0;i
在这种情况下,TestSave将在多个线程上并行执行,从而获得性能优势。您已经看到了。通过并行化,您可以最大限度地降低一些低效率--可能的延迟。但您现在遇到了吞吐量问题。您可能会达到最大连接池限制,默认情况下为100。尝试在连接字符串中设置
Max Pool Size=1000
,然后再次观察结果(实际上我不建议这样做…)。当然,它仍然不会线性扩展,因为您的数据库在给定的时间范围内只能对同一个表(通常)处理如此多的insert操作。@Evk当我使用Max Pool Size=1000进行测试时,我看不到任何显著的变化。如果池限制为100,这是否意味着for循环100应该在1的时间内完成(因为100个线程同时保存)?如果设置ThreadPool.SetMinThreads(500100),也没有区别?另外,数据库是本地的?我知道什么是异步的,什么是并行的,我知道我在比较什么。我不知道为什么我不能获得预期的并行代码性能。为什么在并行情况下性能改进如此之小?