When to use Async methods in EF Core?
Asked Answered
N

3

9

I'm building an application with an SQL database, with the following CRUD operations:

public Foo Add(Foo foo)
{
    _dbContext.Foos.Add(foo);
    _dbContext.SaveChanges();
    return foo;
}

public Foo Delete(int id)
{
    Foo foo = _dbContext.Foos.Find(id);
    if(foo != null)
    {
        _dbContext.Foos.Remove(foo);
        _dbContext.SaveChanges();
    }
    return foo;
}

However, some of these methods have asynchronous versions. The following still works:

public async Task<Foo> Add(Foo foo)
{
    await _dbContext.Foos.AddAsync(foo);
    await _dbContext.SaveChangesAsync();
    return foo;
}

public async Task<Foo> Delete(int id)
{
    Foo foo = await _dbContext.Foos.FindAsync(id);
    if(foo != null)
    {
        _dbContext.Foos.Remove(foo);
        await _dbContext.SaveChangesAsync();
    }
    return foo;
}

Is it only necessary when you still need the variable after calling the method?

As in Foo foo = await _dbContext.Foos.FindAsync(id);

What if I'm passing in a list of Foos to add to the database?

Nevers answered 10/6, 2020 at 20:13 Comment(0)
G
7

Is it only necessary when you still need the variable after calling the method?

Generally speaking, if there are asynchronous APIs, then you should use them for new code.

Asynchronous code frees up the calling thread. If your application is a GUI application, this can free up the UI thread; if your application is a server application, this can free up threads to handle other requests.

Gagliardi answered 10/6, 2020 at 21:35 Comment(5)
I dont understand something for server application. If using DI, a service be created for per request when it's lifetime is scoped. when we consider that a service is usually injected once time during per request, using async is not so important. isn't it. am I missing somethingWaldheim
@M.skr: async has to do with freeing up threads. It doesn't really have anything to do with service lifetimes.Gagliardi
100% as @StephenCleary says, if there's an Async version (and your code is async/can be made async "all the way") then you should usually use that Async version... however, there are currently various issues with some of the EFCore Async APIs (really the SqlClient, but...) like sometimes 10x, or even 100x slower than the sync version e.g. github.com/dotnet/SqlClient/issues/593 github.com/dotnet/efcore/issues/22331 github.com/dotnet/SqlClient/issues/716 In these case "the recommended workaround is currently to use synchronous I/O." So if perf is important - benchmark!Trinhtrini
...so you may see these sorts of issues when using Microsoft.EntityFrameworkCore.SqlServer as that uses Microsoft.Data.SqlClient which has these problems currently... learn.microsoft.com/en-us/ef/core/miscellaneous/async from MS docs "The async implementation of Microsoft.Data.SqlClient unfortunately has some known issues (e.g. #593, #601, and others). If you're seeing unexpected performance problems, try using sync command execution instead, especially when dealing with large text or binary values."Trinhtrini
@StephenCleary's general rule is a great one though... just adding this here for anyone else struggling with EFCore + SQL atm, and thinking... "surely this should be quicker" like I was before switching to the sync versions in these (pretty particular) cases. Hope that helps someone.Trinhtrini
P
3

The rule of thumb is to use async on any thread that by it's busy type waiting, would hamper other threads. For the use of async will have the operations of waiting to step it aside until the data return.

Hence if you have a web service which handles multiple calls, usage of the async/await is good to implement to keep the web service responsive.

Palladous answered 10/6, 2020 at 20:19 Comment(3)
The actual "rule of thumb" is more complex than this. In general, one would use async await when you want to keep the currently running thread from blocking. This frees the thread for other tasks (like updating the UI), while we await the asynchronous result. There's a good treatment of the subject here. How async await works under the hood is described in detail here.Chihli
this is unclear guidance. By definition a web service written in ASP.net core will invoke each call in its own seperate thread already. What benefit will us using async methods in a CRUD call do for us?Verlie
@Verlie by using Async/Await it lets the system know to not do busy-waiting while waiting for the thread to complete and that thread in effect surrenders a chuck of its operational time to be used by other threads. Hence on a busy web service, the handling of multiple calls are not slowed down by threads actively waiting for db return actions. Because of that signaling provided by async/awiath the system can efficiently handle even more incoming calls.Pyrognostics
T
2

As already stated by others very clearly, usually yes -if you can- you want to use the async versions of methods provided.

However, as of 2023/11/02 do be aware of various issues in Microsoft.Data.SqlClient with bad performance of certain Async methods.

i.e. if you are using EFCore and e.g. Microsoft.EntityFrameworkCore.SqlServer you may see these sorts of issues, as Microsoft.EntityFrameworkCore.SqlServer depends on Microsoft.Data.SqlClient...

From MS docs https://learn.microsoft.com/en-us/ef/core/miscellaneous/async

The async implementation of Microsoft.Data.SqlClient unfortunately has some known issues (e.g. #593, #601, and others). If you're seeing unexpected performance problems, try using sync command execution instead, especially when dealing with large text or binary values.

See async-await-best-practices-in-asynchronous-programming for some excellent advice on general best practice.

Only posting as have wasted a lot of time recently dealing with some of these, and only just realised that (oddly this time) was not my fault. Haha!

If performance is critical - benchmark!

Hope that helps someone else struggling with EFCore (and many millions of rows).

In my particular case I was benchmarking the wrong things (I was not testing the sync versions).

Trinhtrini answered 2/11, 2023 at 11:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.