does last async call in async method require await? - c#

I can't understand if await statement is required when async method call is the last call in my async method. E.g.
public async Task CallAsync(byte[] data)
{
await Call1Async(data);
Call2Async(data);
}
public async Task Call1Async(byte[] data)
{
...
}
public async Task Call2Async(byte[] data)
{
...
}
The above would compile but with a warning "consider applying await to this method". But I think it would be waste of resources to apply await for the last call in the method.
At the same time, if I use return Call2Async(data); instead of just Call2Async(data);, the warning would go away. This indicates await is not actually required in such situation.
But this only works for methods which have a return value (i.e. Task<T> rather than just Task). I need this for methods without return values. Is there any way to do the same for value-returning methods?
I.e. I need to somehow return Task object returned by Call2Async to the caller of CallAsync and I can't use return statement in CallAsync explicitly as my methods don't have return values. Of course, I can adjust them all to return values (e.g. true) but it would not be an elegant solution.
P.S. If I have the only async call in my method, I just don't add 'async' to the method signature, and it works ('return' statement not required). But if the method contains more than one async call, I need to have 'async' modifier to be able to await for the first call 'await Call1Async(data)'. And adding 'async' modifier makes the compiler require 'return' to return Task object to the caller (and this works only for methods with return values). That's what I'm trying to overcome.

In the following method:
public async Task CallAsync(byte[] data)
{
await Call1Async(data);
Call2Async(data);
}
Control from the method returns after beginning Call2Async. That is, if you were to await CallAsync(data), it would finish before Call2Async ends. This is probably not what you intended. This method will only finish when both calls are complete:
public async Task CallAsync(byte[] data)
{
await Call1Async(data);
await Call2Async(data);
}
You can see the difference in these example outputs (I implemented the two async calls to simply print a start, delay for a second, and then print an end).
void Main()
{
Console.WriteLine("Main start");
CallAsync(null).Wait();
Console.WriteLine("Main end");
}
The method without the second await prints:
Main start
Call1Async start
Call1Async end
Call2Async start
Main end
Call2Async end
And with the second await:
Main start
Call1Async start
Call1Async end
Call2Async start
Call2Async end
Main end
This implementation also has a problem:
public Task CallAsync(byte[] data)
{
Call1Async(data);
return Call2Async(data);
}
It kicks off both async calls at the same time, but then returns control when Call2Async completes, whether Call1Async is complete or not. Again, this is probably not what you intended.

async keyword indicates that the method is asynchronous and than it will contain the await keyword in it.
I don't understand why you have multiple asynchronous methods?
Consider the following example :
async void MyMethod()
{
Task<object> result = MyWorkAsync();
MyIndependentOtherWork();
object res = await result;
}
Calling MyWorkAsync is like creating a thread "toto" to execute the method (i.e Thread.Start(MyWorkAsyn))
The await keyword is like making a join form the current thread to the thread "toto" and than getting the result of "toto", and in the mean time you get your other independent work to execute on the current thread

Related

Using async/await in a task [duplicate]

I think I missunderstanding the behaviour of async await in c#.
I have two methods that return a Task defined like
public async Task Name()
{
await AsyncOperation()
}
Imagine AsyncOperation() like an PostAsync of HttpClient.
Now I call them inside some other methods
public asyn Task Method()
{
await Name1(() => { "bla bla"});
await Name2();
Console.WriteLine("Continue");
}
This works as expected to me. Waits until Name1() and Name2() finish and then continues.
Now I need to nest Name1() and Name2(). In fact Name1() is a Please Wait Window that recieve as lambda parameters a slow operation, while Name2() is a slow download of a file. I want the Plese Wait window appears while the file is downloaded.
So I try something like this:
public asyn Task Method()
{
await Name1( async ()=>
{
await Name2();
}
Console.WriteLine("Continue");
}
In this case the execution doesnt wait untile Name2() finished. Why this happen and await doesnt wait?
Update
This is the logic behind the method of please wait. It shows a Please Wait message using Mahapps Dialogs, executes the code that recieves by the lambda, and then close the please wait message.
public static async Task Name1(Action longOperation)
{
_progressController = await _metroWindow.ShowProgressAsync("Please wait...");
await Task.Run(() => longOperation());
await _progressController.CloseAsync();
}
The Name1 method takes a delegate and returns a Task<T> where T is the type returned by the delegate. In your case, the delegate returns Task, so we get Task<Task> as the result. Using await waits only for the completion of the outer task (which immediately returns the inner task) and the inner task is then ignored.
You can fix this by dropping the async and await in the lambda function.
Also, take a look at Asynchronous Gotchas in C#.

Lack of await warning in async method that has await in a lambda

Either Visual Studio is confused, or I am (probably me).
If I have
public async Task<Response> DoSomething()
{
//stuff
listOfStuff.ForEach(async s => await _repo.DoThing(s));
return new Response(listOfStuff.Count);
}
It complains that
This async method lacks 'await' ...
However if I change my method to
public async Task<Response> DoSomething()
{
//stuff
foreach (var s in listOfStuff)
{
await _repo.DoThing(s);
}
return new Response(listOfStuff.Count);
}
Then it is perfectly happy and the warning goes away.
So twofold question, is the warning correct and if it is, what is the reasoning for the difference? I'm under the impression that the two methods are intrinsically the same, if the warning is correct, then I must assume that my impression is wrong.
In the first version, the DoSomething function lacks an await operator. The only await is within the async void lambda passed to the ForEach method. In the second version the DoSomething function has an await as part of the actual body of the function and thus you get no warning. It doesn't matter if the listOfStuff may or may not be empty, the condition that the method needs an await is satisfied.
Now the functional difference may not be immediatly clear but it is critical. As stated the first version uses an async void method. That is un-awaitable and the method will therefore continue before the async operation completes as you can see with this test:
[Test]
public void DoSomething()
{
var sw = Stopwatch.StartNew();
var list = Enumerable.Range(0, 10).ToList();
list.ForEach(async x => await Task.Delay(TimeSpan.FromSeconds(1)));
Console.WriteLine($"{sw.ElapsedMilliseconds}ms");
}
Result 6ms, not the 10 seconds we'd expect. The second version of your code is a properly awaitable async Task:
[Test]
public async Task DoSomething()
{
var sw = Stopwatch.StartNew();
var list = Enumerable.Range(0, 10).ToList();
foreach(var x in list)
{
await Task.Delay(TimeSpan.FromSeconds(1));
}
Console.WriteLine($"{sw.ElapsedMilliseconds}ms");
}
And we see the result is: 10032ms right within expectations.
If we replace the lambda with a local function, things may become clearer:
public async Task<Response> DoSomething()
{
//stuff
listOfStuff.ForEach(ProcessStuffAsync);
return new Response(listOfStuff.Count);
async Task ProcessStuffAsync(Stuff s) // local function
{
await _repo.DoThing(s);
}
}
The DoSomething method returns a Task, but it is not really asynchronous because it lacks an await. So the Task returned will be in a completed state. All code inside DoSomething (excluding the code inside the local function) will run synchronously.
The local function ProcessStuffAsync is trully asynchronous, and will return one Task each time is called. These tasks are neither awaited nor stored somewhere inside the DoSomething method, so they are fire-and-forget tasks. Nobody knows what's gonna happen to them.
Update: The code above doesn't compile because List.ForEach cannot accept the ProcessStuffAsync local function as argument. The compiler complains that it has wrong return type. To make the code compile, the local function must return void. But async void functions are a can of worms by themselves.

Does calling await on a no task creation method do anything Asynchronous?

Consider the following:
public async Task<bool> DoSomethingAsync()
{
// no creation of a task in these statements
statement2;
statement3;
statement4;
return Task.FromResult( true );
}
public async Task MyMethod()
{
statement1;
await DoSomethingAsync().ConfigureAwait( false );
statement5;
}
Is there any asynchronous behaviour to be run when awaiting DoSomethingAsync?
Is there any asynchronous behaviour to be run when awaiting DoSomethingAsync?
No, there isn't. When DoSomthingAsync is called, it is executed whole and returned Task is already finished. So when await tries to wire-up the callback logic, it finds out the task is already finished and just continues execution without bothering with the callback logic.
But all of those are implementation details and it is possible those details will change. You should not build your code with the assumption this code will run synchronously. Any addition of await inside DoSomthingAsync will make the code completely asynchronous without you noticing.
Also, DoSomthingAsync the way it is right now does not compile. You either remove the async, in which case it is clear that DoSomthingAsync is not asynchronous. Or you just have return true; , in which case the compiler should warn you that method does not contain any await and will complete synchronously.
Considering your question in comment:
public async Task<bool> DoSomethingAsync()
{
statement2;
await statement3; // << Diverges here
statement4;
return true;
}
// all code below this line is completely irrelevant
// to whenever or where the code above diverges
public async Task MyMethod()
{
statement1;
await DoSomethingAsync().ConfigureAwait( false );
statement5;
}

Passing a task as parameter

I am not sure whether this is possible, so here me out:
I have a sequence of action to perform multiple
async Task MethodA(...)
{
// some code
// a call to specific Async IO bound method
// some code
}
there are also MethodB(), MethodC(), etc, and all of the have exactly the same code, except for the call to specific Async IO bound method. I am trying to find a way to pass a task pointer to a method, so that we can execute it later in a Method().
What i am currently doing is this:
private async Task Method(Func<Task<Entity>> func)
{
// some code
var a = await task.Run(func);
// some code
}
var task = async () => await CallToIOBoundTask(params);
Method(task);
This code, however, pulls a new thread each time, which is not required for IO bound task, and should be avoided.
So, is there a way to refactor the code so that no ThreadPool thread is used? A goal is to have a code like this:
private async Task Method(Task<Entity> task)
{
// some code
var a = await task;
// some code
}
It is also important to mention that different IO calls have different method signatures. Also, a task can start to execute only in Method() body, and not before.
Of course, simply invoke the func, get back a task, and await it:
async Task Method(Func<Task<Entity>> func)
{
// some code
var a = await func();
// some code
}
Also, when you're sending that lambda expression, since all it's doing is calling an async method which in itself returns a task, it doesn't need to be async in itself:
Method(() => CallToIOBoundTask(params));
That's fine as long as all these calls return Task<Entity>. If not, you can only use Task (which means starting the operation and awaiting its completion) and you won't be able to use the result.

Looking for guidance to understand how asynchronous Programming with Async and Await works

i go through a msdn sample code where a function is called when button is clicked and when routine is called then Await keyword is used and function has async keyword used.
private async void StartButton_Click(object sender, RoutedEventArgs e)
{
int contentLength = await AccessTheWebAsync();
resultsTextBox.Text +=
String.Format("\r\nLength of the downloaded string: {0}.\r\n", contentLength);
}
async Task<int> AccessTheWebAsync()
{
HttpClient client = new HttpClient();
Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");
DoIndependentWork();
string urlContents = await getStringTask;
return urlContents.Length;
}
void DoIndependentWork()
{
resultsTextBox.Text += "Working . . . . . . .\r\n";
}
When AccessTheWebAsync is called then await keyword is used, what does it mean?
When this function AccessTheWebAsync() will be executing then DoIndependentWork() function is called and i guess here control will be waiting until this function DoIndependentWork() is finished. Am I right?
again there is another statement called
string urlContents = await getStringTask;
why they use here await. if we do not use await here then what would happen?
Please guide me to understand the code that how it is working.
I have an intro blog post here, and the MSDN docs are also extremely good.
You can think of await as "pausing" the method (without blocking the thread) until the awaitable operation completes. When this happens, it returns a task that is not completed to the calling method, so it also has the option to await.
Here's a brief description about async/await methods.
Async Methods:
Caller is not necessarily blocked for the full execution of async
method
Possible return types
void: “fire-and-forget”
Task: allows to await termination of async method
Task<T>: allows to await termination and get result of type T
No ref or out parameter for async methods
Must again contain an await => Otherwise compile warning
await for Tasks
Await termination of a TPL task
Return result of task (if task with
result type)
Must only occur in async methods => Otherwise compile error
An async method is partly synchronous and partly asynchronous
Caller synchronously executes the method until a blocking await
Thereafter, the method rest is asynchronously executed
async & await Mechanism
Efficient
public async Task<int> GetSiteLengthAsync(string url)
{
HttpClient client = new HttpClient(); <= Sync
Task<string> download1 = client.GetStringAsync(url); <= Sync
string site1 = await download1; <= Async (Another thread)
return site1.Length; <= Async (Another thread)
}
Not sure if that simplier for you to understand that in the following way, but this is how it helped myself:
As you can see, the AccessTheWebAsync returns Task<int> but not just int.
If you would have called it without "await", you would just get the Task<int> object as its result. And could do anything further you want (manually) with that task: for instance, to wait until it finishes theTask.Wait(); and obtain the result of int in theTask.Result.
But await does all that instead of you and returns just int: Task<int> => int.
This is it.
from MSDN:
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.await 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.
So when the compiler encounter
int contentLength = await AccessTheWebAsync();
it waits till the AccessTheWebAsync() task is complted
please take a look at this example C# Async,Await
All await does is blocks the thread until the result of an async operation returns.
Edit: sorry when I said block I should have said suspend, since blocking would prevent execution from continuing!
Edit2: As Alex pointed out - I should have probably said "execution is suspended" rather than the thread. Basically "Stuff happens until await returns but the point is it appears you are writing and executing synchronous code"
Since async operations have the potential to be take a while (e.g. web service calls), they tend to use callbacks to return a result.
If you have to handle callbacks in your code it can get a little messy, especially when waiting on multiple async tasks that are dependant on each other. Async/await and Task simplify the code so that you can write async code literally in the order you would read it.
e.g. example standard async code with callbacks:
public int CallSomeServiceAndReturnItsValue()
{
int result = 0;
WebService.SomeAsyncServiceCall((svcResult) => { result = svcResult.Value; });
return result;
}
and if you have multiple calls that need to be chained:
public int CallSomeServiceAndReturnItsValue()
{
int result = 0;
WebService.GetSomeIdentifier((svcResult) =>
{
var identifier = svcResult.Value;
WebService.GetResult(identifier, (anotherResult) =>
{
result = anotherResult.Value;
}
}
);
return result;
}
As you can see, it starts getting messy, the code doesn't really read in an order that feels natural. The alternative is to use callback methods instead of anonymous methods but still, the callback methods are far away from the code that called them and things can feel disjointed
The other alternative is of course async/await which is much clearer
public int CallSomeServiceAndReturnItsValue()
{
int identifier = await WebService.GetSomeIdentifier();
return await WebService.GetResult(identifier);
}

Categories