Reputation: 4339
Let's say I have an async method that uses Entity Framework to fetch stuff from the database. For example:
public async Task<MyEntity> Get(string bar){
return await db.MyEntities.Where(x=>x.Foo==bar).SingleOrDefaultAsync();
}
This is mainly going to be used by an async MVC or Web API controller, and that works fine. But maybe I also occasionally want to use it in a console app, which doesn't have an async method. I can do that by using Task.Run
private static async Task MainAsync()
{
using(MyEntityService repo=new MyEntityService())
{
MyEntity myEntity=await repo.Get("foobar");
//do stuff
}
}
public static void Main()
{
Task.Run(async () =>
{
await MainAsync();
}).Wait();
}
My question is: is there a downside to doing this compared to implementing a non-async version of the Get
method? Assuming I'm comfortable with this level of code complexity, are there performance reasons a non-async method could be better?
Upvotes: 1
Views: 1637
Reputation: 391326
Before I try to give something that resembles an answer to your question I feel like I need to make you aware of an important issue, and that is that with C# 7.1 or above, you can have an async Main method. You can read more about this in What's new in C# 7.1 but TL;DR, after switching your project to using C# 7.1 or higher, or "latest", you can do this:
public class Program
{
public static async Task Main(string[] args)
{
using(MyEntityService repo=new MyEntityService())
{
MyEntity myEntity=await repo.Get("foobar");
//do stuff
}
}
}
Now, let's try to answer your question. Bear in mind that my knowledge about async/await might be flawed/incomplete, so other answers that does a better job of it may surface.
With that out of the way, what is the most important thing async will add to your code? Complexity.
Any time you declare a method as async
, the whole method compilation changes. The whole thing is turned into a state machine and be rewritten and moved. If you later decompile your program, unless the decompiler is of the really advanced type, the decompiled code will look nothing like your original program.
Now, will this state machine add noticeable overhead to program execution, in terms of execution time or memory usage? No, not really.
A different question would be how much overhead using the async version vs. the non-async version would add, and there is no way of answering that. The whole machinery and all the different options might mean that there is a lot, or there might be almost none, it depends on the actual API you're using and what/how it is doing.
One of the issues you will have to deal with is when it comes to exceptions. Stack traces becomes ... interesting ... when you involve methods declared as async
.
For instance, given this short program (that I ran using LINQPad):
async Task Main()
{
await Test1();
}
public static async Task Test1()
{
await Task.Delay(1000);
throw new Exception("Test");
}
You might expect the stack trace of the exception to contain Main
, but alas, due to the fact that the throw
statement is executed after the task has "resurfaced" after being delayed, it will be executed by some framework code and the stack trace actually looks like this:
at UserQuery.<Test1>d__1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at UserQuery.<Main>d__0.MoveNext()
I guess what you're really looking for are some guidelines about how to deal with async code, and the best I can do are these:
.Wait()
or .Result
to get the result and know exactly what you're doing(Bear in mind that I did not in any way talk about what the methods of the API were doing; my assumption is that if an API provides async methods, there's a reason for it)
Upvotes: 2
Reputation: 7836
Well non-async method will better if you don't have any I/O-bound operations (such as reading from db/disk or network) in your action, because async/await has additional extra cost. Otherwise async action could be a good choice due to release a IIS's thread
Upvotes: 1