문제 : 동시에 시작된 Entity Framework 호출이 처리하는 데 점점 더 길어지는 것을 확인했습니다. 프로그램은 EF 2.2가 포함된 .NET Core 2.2입니다.
다음은 동작을 보여주는 로그의 예입니다.
30번째 쿼리에서 최대 10초까지 진행됩니다.
조사:
이것을 재현하고 테스트하기 위해 Test() 메서드를 병렬로 20번 호출하는 간단한 실행 파일을 만들었습니다. Test()는 ServiceProvider에서 범위가 지정된 컨텍스트를 가져오고 데이터베이스에 쿼리를 수행합니다. 나는 그것을 몇 번 실행했고 각 설정에 대한 3개의 결과에서 스크린샷을 보여주었습니다. 참고: Query() 메서드는 20번의 테스트 전에 한 번 실행되어 EF가 쿼리 캐시를 생성할 수 있도록 합니다.
private async Task Test()
{
List<Task> tasks = new List<Task>();
// Populate the queue.
for (int i = 0; i < 10000; i++)
{
cq.Enqueue(i);
}
Query();
Thread.Sleep(1000);
Query();
Thread.Sleep(1000);
for (int i = 0; i < 20; i++)
{
tasks.Add(Task.Run(() => Query()));
}
await Task.WhenAll(tasks);
}
private async Task Query()
{
cq.TryDequeue(out int id);
Log.Debug($"[{id}] {DateTime.Now.ToString("mm:ss.fff")}: started");
using (var serviceScope = _serviceProvider.CreateScope())
{
var watch = new Stopwatch();
var ctx = serviceScope.ServiceProvider.GetService<Core.Models.MyContext>();
watch.Start();
var quoteLineJob = await ctx.QuoteLineJobs
.FirstOrDefaultAsync(o => o.Id == id);
watch.Stop();
Log.Debug($"[{id}] {DateTime.Now.ToString("mm:ss.fff")}: Quote line job loaded in {watch.ElapsedMilliseconds}ms");
}
}
나는 결과를 이해할 수 없으며 누군가가 가설을 제안할 수 있기를 바랍니다.
로딩이 점점 더 길어집니다.
그러나 동일한 데이터베이스를 적중하면 결과가 훨씬 느립니다.
결과는 개발자의 컴퓨터에서와 매우 유사하지만 점진적으로 작동하지 않고 무작위로 작동할 확률(세 번째 결과 참조)이 50%입니다.
I would like to add that looking at a SQL Server Profiler, for all setup, the read queries take 0ms for all simultaneous queries.
As if this wasn't confusing, when I tried the same test on localhost:
results here are random and not incremented
Again, loading times are random and not incremented
Does anyone see some patterns, and suggestions as to why Entity Framework would behave like this?
My first suggestion would be to determine whether the cause is EF or your service wrapper, depending on how that is implemented. Change your test to this instead and check the performance on the different environments:
var watch = new Stopwatch();
watch.Start();
using (var ctx = new YourAppDbContext(ConnectionString))
{
var quoteLineJob = await ctx.QuoteLineJobs
.FirstOrDefaultAsync(o => o.Id == id);
}
watch.Stop();
Log.Debug($"[{id}] {DateTime.Now.ToString("mm:ss.fff")}: Quote line job loaded in {watch.ElapsedMilliseconds}ms");
If this behaves more predictably then something is suss with your context scope or provider for the DbContext. (unlikely, but without seeing the code, a possibility)
If it is still somewhat variable this is probably a symptom of parallelization. While executing async code, the awaited methods will be setting resume execution points and freeing up the executing thread. .Net will be responding to requests to resume thread operations. Given these operations are already being parallelized into tasks one test would be to make the EF calls synchronously to assess whether more predictable performance comes back. The server's # of cores and overall load situation could greatly effect how 20 or more parallelized are executed.
var watch = new Stopwatch();
watch.Start();
using (var ctx = new YourAppDbContext(ConnectionString))
{
var quoteLineJob = ctx.QuoteLineJobs
.FirstOrDefault(o => o.Id == id);
}
watch.Stop();
Log.Debug($"[{id}] {DateTime.Now.ToString("mm:ss.fff")}: Quote line job loaded in {watch.ElapsedMilliseconds}ms");
다시 말하지만, 이는 성능 문제의 잠재적 원인을 식별하는 데 도움이 될 뿐입니다. async
/ await
더 나은 성능과 같지는 않지만 개별 작업은 느리게 만들지만 요청을 선택하기 전에 완료될 느리거나 빈도가 높은 작업을 기다리지 않고 더 많은 요청을 처리하기 위해 서버 전체를 더 빠르게 처리합니다. 스레드 간의 컨텍스트 전환은 각 작업이 더 느리게 작동하고 서버에 부하가 있을 때 잠재적으로 가변적으로 작동함을 의미합니다. async
상당한 시간이 소요될 것으로 예상되거나 매우 자주 호출될 것으로 예상되는 작업에 대해 작업을 예약 합니다.
이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.
침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제
몇 마디 만하겠습니다