Reputation: 1846
Any idea why this code takes 49 ms
public void OnGet(String sessionId)
{
BackgroundEntry = _context.BackgroundEntry.Where(x => x.Id == sessionId).ToList();
}
but this code takes 300+ ms?
public async Task OnGetAsync(String sessionId)
{
BackgroundEntry = await _context.BackgroundEntry.Where(x => x.Id == sessionId).ToListAsync();
}
I would expect the same time for both. Tested this in various conditions and it always the same, async has 300+ ms delay.
BackgroundEntry is autogen by EF:
public partial class BackgroundEntry
{
public string Id { get; set; }
public string Part { get; set; }
public long Datetime { get; set; }
public DateTime CreatedAt { get; set; }
public Guid Session { get; set; }
public string Action { get; set; }
public string Domain { get; set; }
public string Location { get; set; }
public long? LastEntryDatetime { get; set; }
public BackgroundEntry BackgroundEntryNavigation { get; set; }
public BackgroundEntry InverseBackgroundEntryNavigation { get; set; }
}
benchmark with stopwatch:
using (Models.RecorderContext context = new Models.RecorderContext())
{
sw.Start();
var BackgroundEntry = context.BackgroundEntry.Where(x => x.Id == sessionId).ToList();
sw.Stop();
}
var g = sw.ElapsedMilliseconds;
sw.Reset();
// g = 22 ms
using (Models.RecorderContext context = new Models.RecorderContext())
{
sw.Start();
var BackgroundEntry = await context.BackgroundEntry.Where(x => x.Id == sessionId).ToListAsync();
sw.Stop();
}
g = sw.ElapsedMilliseconds;
// g = 328 ms
Upvotes: 5
Views: 3310
Reputation: 69968
Adding to the answer given by @rducom here and @ChrisPratt. If you are dealing with data 1MB< this issue is still present in Microsoft.EntityFrameworkCore 6.0.0
The blocking part is actually SqlClient
for Async calls and the recommended workaround by @AndriySvyryd that works on the EF core project is:
Don't use VARCHAR(MAX) or don't use async queries.
This happened to me when reading a large JSON object and Image (binary) data with async
queries.
Links:
https://github.com/dotnet/efcore/issues/18571#issuecomment-545992812
https://github.com/dotnet/efcore/issues/18571
https://github.com/dotnet/efcore/issues/885
https://github.com/dotnet/SqlClient/issues/245
https://github.com/dotnet/SqlClient/issues/593
Upvotes: 6
Reputation: 239290
It's impossible to say exactly without more context, but in general, I think you're incorrectly assuming that async should be faster, when in fact it's the opposite.
Async is about scale, not performance. It allows you to use server resources more efficiently, but there is a cost, even if only minimal, to performance for that. There's overhead involved in handling async, thread-switching, etc., all of which can make the same operation actually slower than an equivalent sync operation. However, sync provides no opportunity to use the thread for other work when it's idle, so you're hamstringing your potential server throughput by using sync operations. It's a trade-off that generally falls on the side of async as the best approach.
Upvotes: 2