Multiple Awaitable in one Asynch method - c#

I have an async method Save which internally calls CompleteTaskAsync method as below:
public async void Save()
{
await CompleteTaskAsync();
MessageBox.Show("TaskCompleted");
}
private async Task CompleteTaskAsync()
{
int someResult = await GetResultAsync();//Does some calculation which take few seconds.
await FinalSave(someResult);//Note: This method also interact UI internally
}
CompleteTaskAsync calls two methods in which second method is using output of the first.
In current case MessageBox is coming just after calling first method(GetResultAsync), without calling second method(FinalSave).
I want both await method to be executed before showing the message. Is there any way to execute both await methods before returning to its calling method.

MessageBox.Show("TaskCompleted"); will not be called until the Task instance returned by CompleteTaskAsync is completed, which will in turn not be completed until both of the Task instances returned by GetResultAsync and FinalSave are completed.
Your use of async/await and the behavior you are requesting are consistent. Can you give any more information? I believe your problem does not lie in the code shown.

Related

C# async subsequent calls return existing task

I have web application which calls an external API for data.
If a user triggers this external call, and the call is already in effect, I don't want a second request to trigger a new call, but instead wait for the result of the first call (the result of the call will be the same for both requests).
How can I achieve this in c# using async/ await?
subsequent calls return existing task
Sure, you can do that just by keeping the Task<T> object and then returning it.
Something like:
private async Task<T> ImplementationAsync();
private Task<T> _task;
public Task<T> InterfaceAsync()
{
if (_task == null)
_task = ImplementationAsync();
return _task;
}
This is an extremely simple example. Real-world code should consider:
Can InterfaceAsync be called from multiple threads? If so, then _task needs to be protected.
Is this code loading a resource only one time? If so, then consider using AsyncLazy<T> instead of Task<T>.
Should this code re-load the resource on the next call if the old call has already completed? If so, then the cached Task<T>/AsyncLazy<T> needs to be replaced when the call completes.
Is caching errors OK, or should the next call always retry any previous errors?

Sync call in c#

I have Following API Call in c# and I want to make it Synchronous and it should wait till it comes backs from other modules where delete logic is performed.
I belive the following code is your problem: CallExternalServiceAsync(..)
It should return a task, which you can await if you declare your function async. Otherwise, if you are just interested in waiting, you may call CallExternalServiceAsync(...).Wait(), assuming that it returns a Task.
As stated on comments, you might return a Task instead a void and perform the call of the CallExternalServiceAsync method with the await, assuming it's awaitable.
public async Task CallDeleteOrderApi()
{
var responseMsg = await CallExternalServiceAsync(_apiPath, _validatePath, requestHeader);
}
Have a look at this question which explains how and why using async Task.
Basically, just specify async void return on method declaration when it's on an Event (for example frm_Load on WinForms). On custom methods, always declare it as async Task if you would just return a void (which is actually returning a Task) and async Task<int> if you, for example, want to return an int.

Making async method properly

I googled a lot and for the moment the only async implementation I found (including MSDN site) is the following:
public async void Foo()
{
...
await StreamReader.ReadAsync();
...
}
So in all the cases they use some method which is already async. And this is not what I need.
Let's say that I have a heavy method that does something:
public void DoSomthing()
{
...
}
And there is method where I call this DoSomething:
public void MajorMethod()
{
DoSomething();
}
I want to make DoSomething ayncthonous and call it.
The only solution I see would be the following one:
public Task MajorMethod()
{
return Task.Run(()=>DoSomething());
}
But I read some comments that it's not really the async. So how can I make DoSomething async?
If the MajorMethod has no other things to do other than calling the DoSomething, your code is fine.
But if you need to do other stuff after calling to DoSomething, then mark MajorMethod as async, and use await before Task.Run
public async Task MajorMethod()
{
await Task.Run(()=>DoSomething());
//stuff in here will executed after DoSomething completed
}
Examples from MSDN: Asynchronous programming
or just google c# async
You should be clear about the role async/await play in the Task Asynchronous Pattern. Making an async method does not parform an operation asynchronously just like that. Marking an existing method async will not magically perform everything in there asynchronously. Its main effect is that now you are allowed to use await within the method (I read that it even was discussed if the async keyword was necessary at all; it was added to avoid a breaking change when a local variable in existing methods would be named await).
await also does not provide asynchrony by itself, it provides a way to synchronize to another asnychronous method and yield while the other operation is still running. You can await another async method, but unless somwhere down the chain there is an actual Task running in another thread, the async method might even return synchronously.
In consequence this means that you need an operation that runs asynchronously first (such as a DB query, file access, network communication) and from there you create a chain of async methods that await the previous method.
Now in your case, when you have a computationally intensive method that does not wait for external resources, you can choose to perform the operation asynchronously. Since modern CPUs usually have more than one core at your disposal, you can increase both, performance and application responsiveness like that. The method would not be async, since it does not await anything:
void DoSomething()
{
//...
}
Task DoSomethingAsync() {
return Task.Run(DoSomething);
}
All callers of DoSomethingAsync can now use await to synchronize with this operation running in the background (note the change in return type to Task to allow callers to await):
async Task MajorMethod() {
//...
await DoSomethingAsync();
//...
}
This would allow callers of MajorMethod to synchronize with it. What you can also do is to do stuff in MajorMethod while DoSomethingAsync is running (and still await to allow callers to do even more parallel operations):
async Task MajorMethod() {
//This part will run before DoSomethingAsync
//...
Task doSomethingTask = DoSomethingAsync();
//This part is executed at the same time as DoSomethingAsync
//...
await doSomethingTask; //Here the caller can do more operations while DoSomething is running
//This part will be executed after DoSomethingAsync has finished
//...
}
This form of acquiring a task, doing something and only then awaiting the task has to be done somewhere in the chain, otherwise you have no benefit from the asynchronous operation. Even though this might be an overgeneralization, since synchronization can happen in more subtle ways, for example with a custom synchronization context. But as far as your question is concerned, you should go with: There is an actual task on one end and something that is done after the async call, but before the await on the other end.

Async/Await execution steps

Can anyone explain to me why second Working! shows after Done ?
Stating
Doing Work
Working!
Done
Working!
Work completed
Second question why can't I just do like below to get Task result:
Task result = await LongOperation();
And last question is what would be the reason to use Task.Run on behalf with await/async for instance in my code? Where could it be used or is it not good to use it?
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Starting");
var worker = new Worker();
worker.DoWork();
Console.WriteLine("Done");
Console.ReadKey();
}
}
public class Worker
{
public async void DoWork()
{
Console.WriteLine("Doing work");
await LongOperation();
await LongOperation();
Console.WriteLine("Work completed");
}
private async Task LongOperation()
{
Console.WriteLine("Working!");
await Task.Delay(200);
}
}
This is because you have declared DoWork() asynchronous with a return type of void. This makes it a "fire and forget" method that is running asynchronously. If you have DoWork() return a Task instead of void, you can await it, and that would ensure your "Done" message would occur after DoWork() has completed execution.
Additionally, await unwraps the task result, so you cannot await it and get the value at the same time. If you wish to use the Task result directly, do not await it.
There is no specific area in the code you specified where you should be using Task.Run().
Working shows after Done! because in your static void Main you aren't waiting for worker.DoWork(); to complete, so the program executes the next line. You should change DoWork method like this:
public async Task DoWork()
{
//
}
And change the call to it like this:
worker.DoWork().GetAwaiter().GetResult();
You can't because using await your LongOperation will not return a Task. For example if you had a signature like this, when you use await you unwrap the result:
public Task<int> GiveANumberAsync()
{
return Task.FromResult(12);
}
int result = await GiveANumberAsync();
For this question I think I can't explain better than Stephen in this answer, where he says:
Use Task.Run to call CPU-bound methods.
There reason "Done!" appears sooner than you expect is because you do not have await in front of worker.DoWork(); (and DoWork needs to return a Task to be able to use await). So what happens is DoWork() returns immediately with execution deferred to another thread, and immediately goes to next line which is the console write "done".
Regarding Task result = await LongOperation();, await takes in as parameter awaitable object (i.e. Task), examines its .Result property on your behalf, extracts the result and returns it. So you either drop await to get the task instance, or you put await to wait for task completion and extracting the actual return value of the call.
There are a few reasons to use Task.Run or through task factory, one example being passing lambda function for execution (possibly with closure). I would refer to MSDN library on TPL for detailed dive.
Taking your questions one by one:
In Main, you do not await DoWork. This means that it is invoked, and then execution of the code in the Main continues, without waiting for DoWork to finish. As such, "Done" is printed to the console right away before the second "Working".
This isn't what the await keyword does. From the documentation:
The await operator is applied to a task in an asynchronous method to suspend the execution of the method until the awaited task completes. The task represents ongoing work. [...]
The task to which the await operator is applied typically is the return value from a call to a method that implements the Task-Based Asynchronous Pattern. Examples include values of type Task or Task<TResult>.
Effectively, in order to await a method, it must have return type Task<T>, where T is the actual type of what you return in your code. Your method LongOperation doesn't actually return anything in this example.
Task.Run is used to run any method or block of code as a Task. It can be fired and forgotten (Task.Run([something];), or awaited like any other task (await Task.Run([something]);. See the documentation for it here, though I'm not sure it will be much help. User Stephen Cleary explained it well in this answer, along with some other pertinent information.

Declaring an async method that can be both awaited *and* run asynchrously without waiting for it to finish?

Let's say you're developing an api and want to offer async methods but there's a possibility that the user doesn't actually want to 'await' for a particular async method to finish before continuing to the next line; is there a way of making it "fire and forget"? That is, make it so the method actually runs asynchronously via a Task and have it continue to the next line without 'await'ing? This way if the user wants to await it then they can, and those that want to just run it as a Task can do so.
(Moving my comment to an answer, because I guess it is)
All async methods work that way out of the box. The user is never forced to await anything. It's up to the user to await on your async method or not. You don't need to do anything special to support both cases.
Example:
public async Task MyAsyncMethod() {
// do something asynchronous in here...
}
You can call the method with await:
await obj.MyAsyncMethod();
... or not...
obj.MyAsyncMethod();
In this last case, the method will be a fire-and-forget.
The user can also choose to do the following with your method:
Task t = obj.MyAsyncMethod();
// perform some other tasks that don't depend on the completion of "MyAsyncMethod"
await t; // now I want to await on the task before continuing.
// perform more tasks that require the completion of "MyAsyncMethod"
And as you can see, I didn't need to make any changes to my async method to support all 3 cases.
You have to understand that await does not execute the method. await only registers the continuation of the remaining function in the Task object that is returned by the function. (actually in the Awaiter of the Task object).
So the function is executing, no matter if and how you wait for it's completion. You can store the Task object and await it later. Or you wait for it blocking using the Task.Wait function.

Categories