How should we use async await? [duplicate] - c#

This question already has answers here:
Why use async and return await, when you can return Task<T> directly?
(9 answers)
How and when to use ‘async’ and ‘await’
(25 answers)
Closed 3 years ago.
I was looking at how to use async await, but I do not quite get it when we have multiple methods invoking each other. Should we always use await or should we only use await when we are actually ready to use the result?
So for example should we do it like this:
async Task<string[]> FooAsync()
{
var info = await Func1();
return info.split('.');
}
async Task<string> Func1()
{
return await Func2();
}
async Task<string> Func2()
{
return await tcpClient.ReadStringAsync();
}
Or like this:
async Task<string[]> FooAsync()
{
var info = await Func1();
return info.split('.');
}
Task<string> Func1()
{
return Func2();
}
Task<string> Func2()
{
return tcpClient.ReadStringAsync();
}
Per example 1, should we always use await in every method?
Or
Per example 2 should we only use await on the top-most method when we start using the result?

Every-time you call await it creates a lump of code to bundle up variables, captures the synchronization context (if applicable) and create a continuation into an IAsyncStateMachine.
Essentially, returning a Task without the async keyword will give you a small run-time efficiency and save you a bunch of CIL. Do note that the Async feature in .NET also has many optimizations already. Also note (and importantly) that returning a Task in a using statement will likely throw an Already Disposed Exception.
You can compare the CIL and plumbing differences here
Forwarded Task
Async Method
So if your method is just forwarding a Task and not wanting anything from it, you could easily just drop the async keyword and return the Task directly.
More-so, there are times when we do more than just forwarding and there is branching involved. This is where, Task.FromResult and Task.CompletedTask come into play to help deal with the logic of what may arise in a method. I.e If you want to give a result (there and then), or return a Task that is completed (respectively).
Lastly, the Async and Await Pattern has subtle differences when dealing with Exceptions. If you are returning a Task, you can use Task.FromException<T> to pop any exception on the the returned Task like an async method would normally do.
Nonsensical example
public Task<int> DoSomethingAsync(int someValue)
{
try
{
if (someValue == 1)
return Task.FromResult(3); // Return a completed task
return MyAsyncMethod(); // Return a task
}
catch (Exception e)
{
return Task.FromException<int>(e); // Place exception on the task
}
}
In short, if you don't quite understand what is going on, just await it; the overhead will be minimal. However, if you understand the subtitles of how to return a task result, a completed task, placing an exception on a task, or just forwarding. You can save your self some CIL and give your code a small performance gain by dropping the async keyword returning a task directly and bypassing the IAsyncStateMachine.
At about this time, I would look up the Stack Overflow user and author Stephen Cleary, and Mr. Parallel Stephen Toub. They have a plethora of blogs and books dedicated solely to the Async and Await Pattern, all the pitfalls, coding etiquette and lots more information you will surely find interesting.

Both options are legit and each option has own scenarios where it is more effective then another.
Of course always use await when you want to handle result of the asynchronous method or handle possible exception in current method
public async Task Execute()
{
try
{
await RunAsync();
}
catch (Exception ex)
{
// Handle thrown exception
}
}
If you don't use result of asynchronous method in current method - return the Task. This approach will delay state machine creation to the caller or where ever final task will be awaited. As pointed in the comments can make execution little bit more effective.
But there are scenarios where you must await for the task, even you do nothing with result and don't want handle possible exceptions
public Task<Entity> GetEntity(int id)
{
using (var context = _contextFactory.Create())
{
return context.Entities.FindAsync(id);
}
}
In the scenario above, FindAsync can return not completed task and this task will be returned straight away to the caller and dispose context object created within using statement.
Later when caller will "await" for the task exception will be thrown because it will try to use already disposed object(context).
public async Task<Entity> GetEntity(int id)
{
using (var context = _contextFactory.Create())
{
return await context.Entities.FindAsync(id);
}
}
And traditionally answers about Async Await must include link to Stephen Cleary's blog
Eliding Async and Await

Await is a sequencing feature which allows the caller to receive the result of an async method and do something with it. If you do not need to process the result of an async function, you do not have to await it.
In your example Func1() and Func2() do no process the return values of the called async functions, so it is fine not to await them.

When you use await the code will wait for the async function to finish. This should be done when you need a value from an async function, like this case:
int salary = await CalculateSalary();
...
async Task<int> CalculateSalary()
{
//Start high cpu usage task
...
//End high cpu usage task
return salary;
}
If you hadn't use the the await this would happen:
int salary = CalculateSalary().Result;
...
async Task<int> CalculateSalary()
{
//Start high cpu usage task
... //In some line of code the function finishes returning null because we didn't wait the function to finish
return salary; //This never runs
}
Await means, wait this async function to finish.
Use it to your needs, your case 1 and 2 would produce the same result, as long as you await when you assign the info value the code will be safe.
Source: https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/index

I believe the 2nd one will do because await is expecting a return value.
Since it is waiting for the Func1() to return a value, Func1() is already executing Func2() which is returning a value.

Related

await on task to finish, with operations after the 'await'

I know I may be downvoted but apparently I just don't understand async-await enough and the questions/answer I found, and the articles I found, didn't help me to find an answer for this question:
How can I make "2" to be printed out? Or actually, WHY doesn't 2 gets printed out, both in await t and in t.Wait() ?:
static Task t;
public static async void Main()
{
Console.WriteLine("Hello World");
t = GenerateTask();
await t;
//t.Wait();
Console.WriteLine("Finished");
}
public static Task GenerateTask()
{
var res = new Task(async () =>
{
Console.WriteLine("1");
await Task.Delay(10000);
Console.WriteLine("2");
});
res.Start();
return res;
}
Edit: I'm creating a task and returning it cause in real-life I need to await on this task later on, from a different method.
Edit2: await Task.Delay is just a placeholder for a real-life await on a different function.
Printing '2'
The 2 is actually printed, 10 seconds after 1 is printed. You can observe this if you add Console.ReadLine(); after printing 'Finished'.
The output is
Hello World
1
Finished
2
What is happening?
When you await t (which is res in GenerateTask method) you are awaiting the created Task and not the task that res created.
How to fix (fancy way)
You will need to await both the outer task and inner task. To be able to await the inner task you need to expose it. To expose it you need to change the type of the task from Task to Task<Task> and the return type from Task to Task<Task>.
It could look something like this:
public static async Task Main()
{
Console.WriteLine("Hello World");
var outerTask = GenerateTask();
var innerTask = await outerTask; // what you have
await innerTask; // extra await
Console.WriteLine("Finished");
Console.ReadLine();
}
public static Task<Task> GenerateTask() // returns Task<Task>, not Task
{
var res = new Task<Task>(async () => // creates Task<Task>, not Task
{
Console.WriteLine("1");
await Task.Delay(TimeSpan.FromSeconds(10));
Console.WriteLine("2");
});
res.Start();
return res;
}
The output now is:
Hello World
1
2
Finished
How to fix (easy way)
The outer task is not needed.
public static async Task Main()
{
Console.WriteLine("Hello World");
var t = GenerateTask();
await t;
Console.WriteLine("Finished");
Console.ReadLine();
}
public static async Task GenerateTask()
{
Console.WriteLine("1");
await Task.Delay(TimeSpan.FromSeconds(10));
Console.WriteLine("2");
}
It looks like it's because the constructor to new Task only takes some form of an Action (So the Task never gets returned even though it's async). So essentially what you're doing is an Async void with your delegate. Your await Task.Delay(10000) is returning and the action is considered 'done'.
You can see this if you change the await Task.Delay(10000) to Task.Delay(10000).Wait() and remove the async from the delegate.
On another note though, I've never personally seen or used new Task before. Task.Run() is a much more standard way to do it, and it'll allow for the await to be used. Also means you don't have to call Start() yourself.
Also you might already know this but, in this specific case you don't need a new task at all. You can just do this:
public static async Task GenerateTask()
{
Console.WriteLine("1");
await Task.Delay(10000);
Console.WriteLine("2");
}
Regarding your edits
Replacing your GenerateTask with what I wrote should do what you want. The async/await will turn your method into a Task that has started execution. This is exactly what you are trying to do so I'm not quite sure what you are asking with your edits.
The task returned from GenerateTask can be awaited whenever you want, or not awaited at all. You should almost never need to do new Task(). The only reason I can think is if you wanted to delay execution of the task until later, but there would be better ways around it rather than calling new Task().
If you use the way I showed in your real-life situation, let me know what doesn't work about it and I'll be happy to help.
You should use Task.Run() rather than creating a Task directly:
public static Task GenerateTask()
{
return Task.Run(async () =>
{
Console.WriteLine("1");
await Task.Delay(10000);
Console.WriteLine("2");
});
}
Task.Start() doesn't work because it doesn't understand async delegates, and the returned task just represents the beginning of the task.
Note that you can't fix this by using Task.Factory.StartNew() either, for the same reason.
See Stephen Cleary's blog post on this issue, from which I quote:
[Task.Factory.StartNew()] Does not understand async delegates. This is actually the same as
point 1 in the reasons why you would want to use StartNew. The problem
is that when you pass an async delegate to StartNew, it’s natural to
assume that the returned task represents that delegate. However, since
StartNew does not understand async delegates, what that task actually
represents is just the beginning of that delegate. This is one of the
first pitfalls that coders encounter when using StartNew in async
code.
These comments also apply to the Task constructor, which also doesn't understand async delegates.
However, it's important to note that if you are already awaiting in the code and you don't need to parallelise some compute-bound code, you don't need to create a new task at all - just using the code in your Task.Run() on its own will do.

Can I run sync code as async to gain performance? [duplicate]

This question already has answers here:
Why use async and return await, when you can return Task<T> directly?
(9 answers)
Closed 2 years ago.
I've read a bunch of forums, tutorials and blogs talking about the usage of Async/Await in C#. The more I read the more confusing it gets.
Also, people mainly talk about calling async stuff in a sync method but not calling sync stuff in an async method.
As I am a junior developer and do not have much experience with async programming I'll post a new question here and hope for some enlightenment.
Consider this:
I have a Web API endpoint that does some calculations and model building and returns some data.
public async Task<JsonResult> GetData()
{
Task<Data> stuff1Task = CalculateStuff1();
Task<Data> stuff2Task = CalculateStuff2();
Task<Data> stuff3Task = CalculateStuff3();
return Json(
new
{
stuff1 = await stuff1Task,
stuff2 = await stuff2Task,
stuff3 = await stuff3Task
}, JsonRequestBehavior.AllowGet
);
}
private async Task<Data> CalculateStuff1()
{
return await SomeAsyncCalculation();
}
private async Task<Data> CalculateStuff2()
{
return SomeSyncCalculation();
}
private async Task<Data> CalculateStuff3()
{
Task<Data> dataTask1 = SomeAsyncCalculation();
Task<Data> dataTask2 = AnotherAsyncCalculation();
Data data1 = await dataTask1;
Data data2 = await dataTask2;
Data combindedData = SyncMethodToCombineData(data1, data2);
return combindedData;
}
Why I consider mixing async and sync code is for getting better performance.
In this case lets pretend SomeAsyncCalculation(), SomeSyncCalculation() and AnotherAsyncCalculation() are pretty costly methods. My goal is to get the methods to run somewhat in parallel to gain some faster response times.
I know it is best to go "Async all the way" but lets be real, rebuilding half the project is not always a priority or a possibility.
Also I might have some integrations with other systems that do not support async operations.
This warning I get for CalculateStuff2() adds to the confusion. :
this async method lacks 'await' operators and will run synchronously
In my understanding the "async" keyword is only good for wrapping the method and allowing me to use await keyword. It also allows me to just return the data and I don't need to manage Task returning results. It also handles exceptions.
The Task<TResult> return type is what makes the method execute on a different thread (although it is not guaranteed it will execute on a different thread).
Concluding questions:
1. Will the async method that does not use await (CalculateStuff2()) run synchronously on it's own thread (if it runs on another thread because it is a Task) or will it run in the main thread of the API call, and always block it no matter what?
2. Is it bad practice to use async without await just to have a nicely wrapped task method out of the box?
You're not need for async in sync method. async generates State Machine that is a kind of redundancy in case you're not need for await.
Consider this somewhat optimized example.
public async Task<JsonResult> GetData()
{
Task<Data> stuff1Task = CalculateStuff1();
Task<Data> stuff3Task = CalculateStuff3();
Data stuff2data = CalculateStuff2(); // run sync method after launching async ones
return Json(new
{
stuff1 = await stuff1Task,
stuff2 = stuff2data,
stuff3 = await stuff3Task
}, JsonRequestBehavior.AllowGet);
}
private Task<Data> CalculateStuff1() // optimized
{
return SomeAsyncCalculation();
}
private Data CalculateStuff2()
{
return SomeSyncCalculation();
}
private async Task<Data> CalculateStuff3()
{
//use combinator to simplify the code
Data[] data = await Task.WhenAll(SomeAsyncCalculation(), AnotherAsyncCalculation());
Data combindedData = SyncMethodToCombineData(data[0], data[1]);
return combindedData;
}
Also consider to differ the CPU-bound and IO-bound operations, look at this article. There's different async approach depending on what exacly you're launching.
Direct answers
Will the async method that does not use await (CalculateStuff2()) run synchronously on it's own thread (if it runs on another thread because it is a Task) or will it run in the main thread of the API call, and always block it no matter what?
Yes, it will run synchronously on the caller Thread. If you want to run some sync method on its own Thread, use Task.Run():
Task<Data> stuff2Task = Task.Run(() => CalculateStuff2());
and then await it.
Is it bad practice to use async without await just to have a nicely wrapped task method out of the box?
Yes, it's bad practice. Redundant State Machine makes overhead which in this case is worthless.

Whether the calling thread will be blocked if Task.Result is called in the Task returning function

I try to not create redundant Task objects in my code and I write Task returning functions instead of async Task functions where it is possible.
When it is necessary to save value returned by an async function, I am forced to make the function return async Task and call function with await.
Example:
async Task SomeWorkAsync()
{
someGlobalVariable = await AnotherWorkAsync();
}
What I wrote instead:
Task SomeWorkAsync()
{
var task = AnotherWorkAsync();
someGlobalVariable = task.Result;
return task;
}
But I am afraid that it will block calling thread as synchronous code does.
await SomeWorkAsync(); //main thread block
Is there another way to rewrite the code in example without wrapping a whole function with new Task as async keyword does?
I try to not create redundant Task objects in my code and I write Task returning functions instead of async Task functions where it is possible.
That's not common nor the intended way of working with the TPL.
This is wrong:
Task SomeWorkAsync()
{
var task = AnotherWorkAsync();
someGlobalVariable = task.Result;
return task;
}
You should be using
async Task<T> SomeWorkAsync()
{
someGlobalVariable = await AnotherWorkAsync();
return someGlobalVariable;
}
Only under strict circumstances should you use .Result to get the result of a Task.
To answer your question:
Yes, calling .Result will block your thread.
See my comment on why I think it's better to use await and not to return a task: https://stackoverflow.com/a/54211382/918058
If you want to save your self a state machine, just call
public Task SomeWorkAsync()
{
...
return AnotherWorkAsync();
}
Don't call Result, just return the task through without the async keyword in the method definition
In short, you are just returning a task, that can be awaited higher up
Update
Yes this does the trick if AnotherWorkAsync is async Task but in my
case it is async Task<T>
public Task<MyAwesomeType> SomeWorkAsync()
{
...
return AnotherWorkAsync();
}
Update 2
This is still not what I mean. Class which will call SomeWorkAsync
doesn't know anything about private variable someGlobalVariable. It is
necessary to get value and set this variable inside
public async Task SomeWorkAsync()
{
someGlobalVariable = await AnotherWorkAsync();
}
If you need the result from the async method you will have to await it.
Try not to mix synchronous code and the async await pattern, which you are doing with Result, you can cause deadlocks... just let async propagate

does the last call in 'async' call graph need to be synchronous?

For example, in the code below, the last method M2Async is synchronous and does not have async/await as otherwise there would need to be a call to M3Async after await and the call graph would continue?
For clarity (from C# in a Nutshell):
A synchronous operation does its work before returning to the caller.
An asynchronous operation does (most or all of) its work after returning to the caller.
public void Main()
{
Task task = M1Async();
// some work
int i = task.result;
// use i etc
}
private async Task M1Async()
{
int i = await M2Async();
// some work
return i;
}
private Task M2Async()
{
return Task.FromResult(2);
}
That depends a bit on what you mean by "synchronous". In some ways, all methods are synchronous (even async ones) - they just synchronously return something that can be awaited and which might have more things to do once awaited.
No, it doesn't have to be synchronous; your code could just as well be:
private async Task<int> M2Async()
{
return await Task.FromResult(2);
}
or even just (although the compiler will detect that this is a smell, and is secretly synchronous):
private async Task<int> M2Async()
{
return 2;
}
Neither of which would be particularly useful, but; they would work. In reality, most async methods will bottom out at something that is doing async IO - file-system, network, etc. In your example, there is nothing that will actually truly be async anyway - it will all be completed when the await is reached.

Adding a synchronous caching mechanism to an async method "transparently"

I have a method which does a long action using an async task
Now, I want to add a cache mechanism that will be transparent in the same method.
Now, I could always fetch my cache result and wrap it with a Task so it will "work" but I want to prevent the context switch that I will get.
Here's an example of what I have:
var result = await LongTask();
private async Task<string> LongTask()
{
return await DoSomethingLong();
}
And here's an example of what I want:
var result = await LongTask();
private async Task<string> LongTask()
{
if(isInCache)
{
return cachedValue(); // cache value is a const string you can do return "1" instead.
}
// else do the long thing and return my Task<string>
return await DoSomethingLong();
}
Now I'm surprised to see that this compiled and worked
Something tells me that I'm not doing it correctly.
Here's another similar example that I've tested:
private async Task<string> DownloadString(bool sync)
{
using (WebClient wc = new WebClient())
{
var task = wc.DownloadStringTaskAsync("http://www.nba.com");
if(sync)
return task.Result;
return await task;
}
}
And here's the code:
var res = DownloadString(true);
string str1 = await res;
var res2 = DownloadString(false);
string str2 = await res2;
From what I've read here task.Result executes the task synchronously and returns a string.
Now I see the request via Fiddler and my program get's stuck on the return task.Result line even though I see a 200 OK and I wait a long time.
Bottom Line:
Whats the best\correct way to use caching inside an async method(e.g. doing something synchronously in some cases without create a context switch overhead?
Why does my second block of code with the DownloadString get stuck?
First of all, if after a call to an async method the returned task is already completed there would be no context switch, because none is needed. So this is completely acceptable:
private async Task<string> LongTask()
{
if(isInCache)
{
return cachedValue(); // cache value is a const string you can do return "1" instead.
}
// else do the long thing and return my Task<string>
return await DoSomethingLong();
}
However, in the cases where the result is cached, the async mechanism is redundant. This overhead is mostly negligible but you can improve performance by dropping both the async and await and create a completed task using Task.FromResult:
private Task<string> LongTask()
{
if(isInCache)
{
return Task.FromResult(cachedValue());
}
// else do the long thing and return my Task<string>
return DoSomethingLong();
}
...when you write “await someObject;” the compiler will generate code that checks whether the operation represented by someObject has already completed. If it has, execution continues synchronously over the await point. If it hasn’t, the generated code will hook up a continuation delegate to the awaited object such that when the represented operation completes, that continuation delegate will be invoked
From Async/Await FAQ
Task.Result doesn't execute the task synchronously, it waits synchronously. That means that the calling thread is blocked waiting for the task to complete. When you use that in an environment with a SynchronizationContext that may lead to a deadlock since the thread is blocked and can't handle the task's completion. You shouldn't use the Result property on a task that hasn't completed yet.

Categories

Resources