Calling Async Method from Sync Method - c#

I see a lot of questions about calling asyc methods from sync ones, like here: How to call asynchronous method from synchronous method in C#?
I understand the solutions however, experimentally, I am seeing that I don't need to add a .Wait() or Task.Run(async () => await MyAsyncMethod()) for it to run synchronously. I have a get method that pulls information from a DB.
My code is below and when I run, it waits at var task = GetItemAsync() and I get the correct result from the DB. I find it hard to believe that the DB call could come back before the code would move on which seems to imply that it ran synchronously. Am I missing something?
public object GetItem()
{
var task = GetItemAsync();
var result = task.Result;
return result
}

See The docs on Task<>.Result
System.Threading.Tasks.Task.Result is a blocking call that waits until the task finishes. So it has a built in wait call essentially.
In the remarks section of that microsoft doc:
Accessing the property's get accessor blocks the calling thread until the asynchronous operation is complete; it is equivalent to calling the Wait method.
It's unfortunate that Microsoft did not reflect this in the name of the accessor because it's an extremely critical side effect of this accessor.

The only right way to call awaitable(method which returns Task) method is to await it. But you can await only within the method which returns Task. In legacy code it happens you cannot change the method signature because you have too many reference and you need to basically refactor entire code base. So you have these options:
.Result
.Wait()
.GetAwaiter().GetResult()
Neither of those are good. All of them are going to block the thread. But if you cannot change the method signature to await the execution, I would pick the last option - GetAwaiter().GetResult() becasue it will not wrap the exception into AggregateException

Related

async await vs Result from higher level call?

I have this simple repository method:
public async Task<Blog> GetById(int id)
{
return await _dbContext.Blogs.FirstOrDefaultAsync(p => p.Id == id);
}
I read some answers about async await, but I still don't understand how to call this GetById method properly:
public async Task DoSomething1()
{
var blog = await _blogRepository.GetById(1);
Console.WriteLine(blog.Title);
}
or
public void DoSomething2()
{
var blog = _blogRepository.GetById(1).Result;
Console.WriteLine(blog.Title);
}
Properly means: without blocking the thread like described in this post:
https://msdn.microsoft.com/en-us/magazine/dn802603.aspx?f=255&MSPPError=-2147217396
Personally I think, that correct way is DoSomething2 in this situation.
Because thread blocking happens when FirstOrDefaultAsync is running, so this is reason why I use async and await in GetById method, so is it really need to use one more async await in higher methods like in DoSomething1? can I use Result in this situation like in DoSomething2?
What are the advantages and disadvantages of choices?
(I use .NET 4.5)
Regarding first implementation(DoSomething1) You can read here:
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/await
An await expression does not block the thread on which it is executing. Instead, it causes the compiler to sign up the rest of the async method as a continuation on the awaited task. Control then returns to the caller of the async method. When the task completes, it invokes its continuation, and execution of the async method resumes where it left off.
Regarding second (DoSomething2)
According to https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task-1.result?redirectedfrom=MSDN&view=netframework-4.7.2#System_Threading_Tasks_Task_1_Result
Accessing the property's get accessor blocks the calling thread until the asynchronous operation is complete; it is equivalent to calling the Wait method.
Once the result of an operation is available, it is stored and is returned immediately on subsequent calls to the Result property. Note that, if an exception occurred during the operation of the task, or if the task has been cancelled, the Result property does not return a value.
To prove it, You can check thread id's before executing and after. For example
var threadId1 = Thread.CurrentThread.ManagedThreadId;
var blogPost = await DoSomething1();
var threadId2 = Thread.CurrentThread.ManagedThreadId;
var blogPost = DoSomething2().Result;
var threadId3 = Thread.CurrentThread.ManagedThreadId;
If You output thread id's, threadId2 and threadId3 in the result will always be the same, so no thread change happens, and the thread is blocked.
{
"threadId1": 30,
"threadId2": 15,
"threadId3": 15
}
It's DoSomething1() that will avoid blocking, not DoSomething2().
You use the async modifier to specify that a method, lambda expression, or anonymous method is asynchronous
An async method runs synchronously until it reaches its first await expression, at which point the method is suspended until the awaited task is complete, in this case, that would be the GetById async method.
You also have an error waiting to happen in your code...
public async Task DoSomething1()
{
var blog = await _blogRepository.GetById(1);
Console.WriteLine(blog.Title); // this line has the bug
}
The GetById method internally uses FirstOrDefault when searching the underlying database, so if you search for a blog that doesn't exist, the method will return a null object... you're then attempting to access that objects Title property, but because its null... you'll get a null reference exception. Check whether the object is null before attempting to access its properties
Task.Result call will block the calling thread until the operation is completed.
Here is an excellent article explains it well
https://montemagno.com/c-sharp-developers-stop-calling-dot-result/
I know this is a controversial topic and I think it deserves controversial answer so here it goes:
First of all, let me make it clear that DoSomething2 is a blocking method; meaning it will run on calling thread and block the calling thread, while DoSomething1 will not block the calling thread and will run on thread pool thread instead.
Now, from my understanding of async methods, their sole purpose is to allow parallelism and hence maximum usage of your CPU. What that means from the desktop developer perspective is, you could have a responsive UI when you call async method and you could update UI while work is being offloaded to non-main thread.
If your application is designed to run units of work in parallel then it makes sense, to me, to use DoSomething1 instead of DoSomething2 as you could get maximum usage out of your CPU, but if your application is designed to run units of work in sequential manner (as I believe you are doing in your console application) you wouldn't be getting any benefit from using DoSomething1 as there will be only one operation running at a time and I would use DoSomething2 instead.
With that being said, you can use AsyncContext.Run(() => MyMethodAsync(args)); in your console app to run your async method on separate context.
To summarize, unless your console app is doing some parallel work on threads, I would say you will be fine using DoSomething2.
P.S you should fix the bug mentioned by #AydinAdn.
if await is applied to the result of a method call that returns a Task Result, then the type of the await expression is Result. If await is applied to the result of a method call that returns a Task, then the type of the await expression is void

Should I use Task.Run to wait tasks in a synchronous context?

I have an ASPX page which I cannot convert to async but which uses some async methods in a synchronous context. The way it invokes them is like so:
public void MySyncMethod()
{
var myTask = Task.Run(() => _myField.DoSomethingAsync());
myTask.Wait();
//use myTask.Result
}
Is there any difference between doing that and the following as far as async/await and/or blocking goes?
public void MySyncMethod()
{
var myTask = _myField.DoSomethingAsync(); //just get the Task direct, no Task.Run
myTask.Wait();
//use myTask.Result
}
I assume a previous developer added the Task.Run for a reason. But I am having issues which accessing things in HttpContext as the work is being run on a different thread.
Is there a reason to use Task.Run here?
Is there any difference between doing that and the following as far as
async/await and/or blocking goes?
Yes the first block of code uses a thread pool thread then waits for this to return, so your using two threads not one. They both block.
I assume a previous developer added the Task.Run for a reason.
Yes, blocking (directly) on async code from an ASP.Net context is a bad idea and can cause deadlocks. So you second block of code is more efficent (in thread usage) but suffers from serious deadlock issues.
The correct solution here is to make public void MySyncMethod() async itself (public async Task MySyncMethod()). Both these solutions have drawbacks and the only real way out is to make the whole call stack async. If you can do this, do it.
If you can't call an async method from another async method then Task.Run is the way to go. See How to call asynchronous method from synchronous method in C#? for more details.
If you want HttpContext inside your thread have a read though Using HttpContext in Async Task I would definitely favour:
Make every thing async
Or the Read the values from the context then pass them
Options of those answers and keep in mind
First off, you're not creating a copy of the object, you're just
copying the reference to the object.HttpContext isn't a
struct.....etc
The internal workings of asynchronous code based on async/await is fundamentally different than tasks started by Task.Run. async/await tasks are promise based and depend on the caller cooperating with returning the execution back to the asynchronous method when appropriate. Tasks started by Task.Run however are usually started on a parallel thread taken from the thread pool and do not depend on the caller's cooperation to continue execution when appropriate.
This constellation leads to the problem that you can not treat a promise based task the same as the other tasks, since the promise based task might wait for the callers cooperation to return the execution, which might never occur since the other task is executed independently and might wait for the caller. The result is a deadlock.
The solution is a specific Task.Run overload that will create a proxy for an existing task-based method that allows proper execution of a promise based task. It is safe to call Wait on this proxy. That's why the other developer used this construct. He could have also simplified the call and avoided an anonymous method like this:
var myTask = Task.Run(_myField.DoSomethingAsync);
Task.Run is used to run code asynchronously.
Be clear that it returns Task and needs to be awaited. Here's an example:
Task myTask = Task.Run(() => DoSomething());
await myTask;

C# Asynchronous call "invoke and forget"

In c# when you invoke the await method inside an async method, the code will be executed from the calling context to that method. What if I want to make an asynchronous call which will just continue from the same line of code directly (even if the asynchronous action did not finish yet) instead of getting back to the calling context? How can I do that?
What if I want to make an asynchronous call which will just continue from the same line of code directly (even if the asynchronous action did not finish yet) instead of getting back to the calling context? How can I do that?
The easiest way, which works whether Something is synchronous or asynchronous:
var _ = Task.Run(() => Something());
But, as Eric Lippert stated:
it is a strange thing to get a task and then not care about what happens when it completes.
Or, as I like to put it: fire-and-forget is almost never what you really want. To "forget" means:
You don't care when it completes.
You don't care whether it completes. E.g., if your app exits (or app pool is recycled if on ASP.NET), then your background work is just lost.
You don't care whether it completes successfully. E.g., if your work throws an exception, you want to silently swallow that exception.
In real-world code, this scenario is extremely rare.
An await is, by definition, a point at which you must asynchronously wait for the task to finish before continuing the workflow. If you don't have to wait, then don't wait! There is no requirement that you await anything.
Your question is rather like asking "I have an IEnumerable<int> but I don't care what integers are in it; do I have to foreach over it?" No, you don't. If you don't care what the result is, you don't have to get a result from a sequence. If you don't care what the result of a task is, you don't have to await it.
But it is a strange thing to get a sequence and then not enumerate it, and it is a strange thing to get a task and then not care about what happens when it completes.
If you want to start the async method and continue inside the function you can do something like Task<string> getStringTask = asyncMethodThatReturnsString();. Then continue until you want to wait for the async task to finish at which point you would call string output = await getStringTask;.

Stop this async function calls, just return simple values instead [duplicate]

This question already has answers here:
C# Task which returns a value
(2 answers)
Closed 6 years ago.
I simply want to return a string from a function where I need to do api calls on windows phone environment. I dont want to return a Task, just a string.
I simply dont know how to get values from functions without always using await at the exact place I call a function that should be simply executed (which makes this entire async/await thing senseless).
Please explain me how I can get something like this:
string TheStringIWant(someParameter)
{
string result = await LoadDataAsync();
return result;
}
Sorry, I'm going to give you the "hard love" answer.
I simply want to return a string from a function where I need to do api calls on windows phone environment. I dont want to return a Task, just a string.
Too bad. The correct solution is to return a Task<string>, especially on a mobile platform. Any other solution is just going to be a hack.
I simply dont know how to get values from functions without always using await at the exact place I call a function that should be simply executed (which makes this entire async/await thing senseless).
It's not senseless at all. async/await is what keeps your UI responsive. This is necessary for your app to be accepted in the Windows Store.
Assuming you are trying to all a function that returns a Task you'd just do this:
var result = LoadDataAsync().GetAwaiter().GetResult();
Of course, this is not forcing the method to run synchronously, rather it is telling the compiler that you want to wait until the asynchronous task completes and then return the results. It is functionally equivalent to
var result = await LoadDataAsync();
All this syntax does is allow you to skip annotating your method with an async keyword. You do need to wait one way or the other. If you are calling a method that runs asynchronously and you need to do something to wait for that function to complete and return the data to you, otherwise you would get bad data.
Just a point of caution, when you make a blocking call on an async method (either by Wait() or .Result) you have the risk of causing a dead lock if the SynchronizationContext of the calling method is not null. Because the async method will attempt to schedule its continuation on the Synchronization Context of the calling method but the calling method blocks on the completion of the async method so you end up in a dead lock.
One way to guarantee no dead lock is to push this async call to a background thread ie. by Task.Run. Background threads do not have SynchronizationContext so no dead lock.
Something like:
var result = Task.Run(async() => await LoadDataAsync()).Result;
ps. You do not need to call Wait() before the Result property. Result will block the thread until task is completed.

Awaiting last method call

A few posts on stack overflow have suggested the following:
Any async method where you have a single await expression awaiting a Task or Task < T >, right at the end of the method with no further processing, would be better off being written without using async/await.
Architecture for async/await
Await or Return
Is this advice just for particular circumstances? On a web server, isn't one of the main reasons to use async/await, being that while awaiting something like the UpdateDataAsync method below, the Thread will return to the ThreadPool, allowing the server to work on other requests?
Should SaveDataAsync await that DB update call given it's the last call in the method?
public async Task WorkWithDataAsync(Data data)
{
ManipulateData(data);
await SaveDataAsync(data);
await SendDataSomewhereAsync(data);
}
public async Task SaveDataAsync(Data data)
{
FixData(data);
await DBConnection.UpdateDataAsync(data);
}
Also, given you don't know where SaveDataAsync will be used, making it synchronous would hurt a method like WorkWithDataAsync would it not?
Removing the await and just returning the Task doesn't make the method synchronous. await is a tool that makes it easier to make a method asynchronous. It's not the only way to make a method asynchronous. It's there because it allows you to add continuations to task much more easily than you could without it, but in the method that you've shown you're not actually leveraging the await keyword to accomplish anything and as such you can remove it and have the code simply function identically.
(Note that technically the semantics of exceptions will have been slightly changed by removing async; thrown exceptions will be thrown from the method, not wrapped in the returned Task, if it matters to you. As far as any caller is concerned, this is the only observable difference.)
Writing these methods without the async-await keywords doesn't make them synchronous.
The idea is to return the task directly instead of having the overhead of generating the state machine.
The actual difference is about exception handling. An async method encapsulates exceptions inside the returned task while a simple task returning method doesn't.
If for example FixData throws an exception it will be captured in an async method but directly thrown in a simple task returning one. Both options would be equally asynchronous.

Categories