Is there any scenario where writing method like this:
public async Task<SomeResult> DoSomethingAsync()
{
// Some synchronous code might or might not be here... //
return await DoAnotherThingAsync();
}
instead of this:
public Task<SomeResult> DoSomethingAsync()
{
// Some synchronous code might or might not be here... //
return DoAnotherThingAsync();
}
would make sense?
Why use return await construct when you can directly return Task<T> from the inner DoAnotherThingAsync() invocation?
I see code with return await in so many places, I think I might have missed something. But as far as I understand, not using async/await keywords in this case and directly returning the Task would be functionally equivalent. Why add additional overhead of additional await layer?
There is one sneaky case when return in normal method and return await in async method behave differently: when combined with using (or, more generally, any return await in a try block).
Consider these two versions of a method:
Task<SomeResult> DoSomethingAsync()
{
using (var foo = new Foo())
{
return foo.DoAnotherThingAsync();
}
}
async Task<SomeResult> DoSomethingAsync()
{
using (var foo = new Foo())
{
return await foo.DoAnotherThingAsync();
}
}
The first method will Dispose() the Foo object as soon as the DoAnotherThingAsync() method returns, which is likely long before it actually completes. This means the first version is probably buggy (because Foo is disposed too soon), while the second version will work fine.
If you don't need async (i.e., you can return the Task directly), then don't use async.
There are some situations where return await is useful, like if you have two asynchronous operations to do:
var intermediate = await FirstAsync();
return await SecondAwait(intermediate);
For more on async performance, see Stephen Toub's MSDN article and video on the topic.
Update: I've written a blog post that goes into much more detail.
The only reason you'd want to do it is if there is some other await in the earlier code, or if you're in some way manipulating the result before returning it. Another way in which that might be happening is through a try/catch that changes how exceptions are handled. If you aren't doing any of that then you're right, there's no reason to add the overhead of making the method async.
Another case you may need to await the result is this one:
async Task<IFoo> GetIFooAsync()
{
return await GetFooAsync();
}
async Task<Foo> GetFooAsync()
{
var foo = await CreateFooAsync();
await foo.InitializeAsync();
return foo;
}
In this case, GetIFooAsync() must await the result of GetFooAsync because the type of T is different between the two methods and Task<Foo> is not directly assignable to Task<IFoo>. But if you await the result, it just becomes Foo which is directly assignable to IFoo. Then the async method just repackages the result inside Task<IFoo> and away you go.
If you won't use return await you could ruin your stack trace while debugging or when it's printed in the logs on exceptions.
When you return the task, the method fulfilled its purpose and it's out of the call stack.
When you use return await you're leaving it in the call stack.
For example:
Call stack when using await:
A awaiting the task from B => B awaiting the task from C
Call stack when not using await:
A awaiting the task from C, which B has returned.
Making the otherwise simple "thunk" method async creates an async state machine in memory whereas the non-async one doesn't. While that can often point folks at using the non-async version because it's more efficient (which is true) it also means that in the event of a hang, you have no evidence that that method is involved in the "return/continuation stack" which sometimes makes it more difficult to understand the hang.
So yes, when perf isn't critical (and it usually isn't) I'll throw async on all these thunk methods so that I have the async state machine to help me diagnose hangs later, and also to help ensure that if those thunk methods ever evolve over time, they'll be sure to return faulted tasks instead of throw.
This also confuses me and I feel that the previous answers overlooked your actual question:
Why use return await construct when you can directly return Task from the inner DoAnotherThingAsync() invocation?
Well sometimes you actually want a Task<SomeType>, but most time you actually want an instance of SomeType, that is, the result from the task.
From your code:
async Task<SomeResult> DoSomethingAsync()
{
using (var foo = new Foo())
{
return await foo.DoAnotherThingAsync();
}
}
A person unfamiliar with the syntax (me, for example) might think that this method should return a Task<SomeResult>, but since it is marked with async, it means that its actual return type is SomeResult.
If you just use return foo.DoAnotherThingAsync(), you'd be returning a Task, which wouldn't compile. The correct way is to return the result of the task, so the return await.
Another reason for why you may want to return await: The await syntax lets you avoid hitting a mismatch between Task<T> and ValueTask<T> types. For example, the code below works even though SubTask method returns Task<T> but its caller returns ValueTask<T>.
async Task<T> SubTask()
{
...
}
async ValueTask<T> DoSomething()
{
await UnimportantTask();
return await SubTask();
}
If you skip await on the DoSomething() line, you'll get a compiler error CS0029:
Cannot implicitly convert type 'System.Threading.Tasks.Task<BlaBla>' to 'System.Threading.Tasks.ValueTask<BlaBla>'.
You'll get CS0030 too, if you try to explicitly typecast it.
This is .NET Framework, by the way. I can totally foresee a comment saying "that's fixed in .NET hypothetical_version", I haven't tested it. :)
Another problem with non-await method is sometimes you cannot implicitly cast the return type, especially with Task<IEnumerable<T>>:
async Task<List<string>> GetListAsync(string foo) => new();
// This method works
async Task<IEnumerable<string>> GetMyList() => await GetListAsync("myFoo");
// This won't work
Task<IEnumerable<string>> GetMyListNoAsync() => GetListAsync("myFoo");
The error:
Cannot implicitly convert type 'System.Threading.Tasks.Task<System.Collections.Generic.List>' to 'System.Threading.Tasks.Task<System.Collections.Generic.IEnumerable>'
Related
What are differences between the 3 calls inside method WhatDifferences?
Here is test code:
async Task WhatDifferences(Context context)
{
await ActionAsync(context, async x => await IsOddAsync(x).ConfigureAwait(false));
await ActionAsync(context, x => IsOddAsync(x));
await ActionAsync(context, IsOddAsync);
}
async Task<T> ActionAsync<T>(Context context, Func<Context, Task<T>> action)
{
return await action(context).ConfigureAwait(false);
}
async Task<bool> IsOddAsync(Context context)
{
return await Task.Run(() => context.Count++ % 2 == 1).ConfigureAwait(false);
}
class Context
{
public int Count { get; set; }
}
I'm trying to decide which one to use in my codebase and based on my knowledge all 3 behave the same.
The question is different with What's the method signature for passing an async delegate?
You may know my concern if I show more logic
async Task<T> ActionAsync<T>(Context context, Func<Context, Task<T>> action)
{
using (var transaction = new TransactionScope())
{
//do some async logic before action
var result = await action(context).ConfigureAwait(false);
//do other async validation logic after action
return result;
}
}
I'm trying to decide which one to use in my codebase and based on my knowledge all 3 behave the same.
In this specific instance, this is essentially true.
This one creates a delegate that refers to the IsOddAsync method:
await ActionAsync(context, IsOddAsync);
This one creates a method for the lambda expression and the delegate refers to that compiler-generated method:
await ActionAsync(context, x => IsOddAsync(x));
And this one does the same, but for an asynchronous lambda, so the compiler-generated method also has an async state machine:
await ActionAsync(context, async x => await IsOddAsync(x).ConfigureAwait(false));
In general, your question boils down to two questions:
Should I use method groups instead of lambdas? Yes, you should. There's no disadvantage to doing so, and it's a tiny bit more efficient, shorter code, without any impact on maintainability.
Should I elide async/await or keep the keywords in? This one is more nuanced.
Eliding async in this particular case is fine, because all the async lambda is doing is calling a single method and passing its parameter. There's no possibility of exceptions being thrown from the lambda before or after the call to IsOddAsync.
However, if your lambda is more complex - doing operations on x before passing it to IsOddAsync, or doing operations on the result, or using a using block, then you'd want to keep the async/await keywords for maximum maintainability. More information here.
await vs return Task
The difference between:
await ActionAsync(context, async x => await IsOddAsync(x).ConfigureAwait(false));
await ActionAsync(context, x => IsOddAsync(x));
In some cases you don't need the await (and also not the async of course)
Methods that perform asynchronous operations don't need to use await if:
There is only one asynchronous call inside the method
The asynchronous call is at the end of the method
Catching/handling exception that may happen within the Task is not necessary
See Returning a Task without await.
In that case you could return the Task intermediately.
Please note there is a small difference in behavior - depending on the implementation of IsOddAsync:
Important: Returning the Task instead of awaiting it, changes the exception behavior of the method, as it won't throw the exception inside the method which starts the task but in the method which awaits it.
As Gabriel Luci noted, with the current implementation of IsOddAsync (one call and an await), there is no difference in behavior.
x => IsOddAsync(x) vs IsOddAsync
The difference between
await ActionAsync(context, x => IsOddAsync(x));
await ActionAsync(context, IsOddAsync);
In the first one your are creating an anonymous (lambda) method with the parameter x. As IsOddAsync has also one parameter (with the same type), there is no need for the lambda method.
Please note you need the lambda if IsOddAsync has other parameters, e.g. and 2nd parameter, then you need the lambda. Example:
await ActionAsync(context, x => IsOddAsync(x, "mySecondParameter"));
In this case there is no difference in behavior, except the callstack when an exception in thrown inside.
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.
I am studying C# Asnc-await pattern and currently reading Concurrency in C# Cookbook from S. Cleary
He discusses wrapping old non TAP async patterns with TaskCompletionSource (TCS) into TAP constructs.
What I dont get is, why he just returns the Task property of the TCS object instead of awaiting it TCS.Task ?
Here is the example code:
Old method to wrap is DownloadString(...):
public interface IMyAsyncHttpService
{
void DownloadString(Uri address, Action<string, Exception> callback);
}
Wrapping it into TAP construct:
public static Task<string> DownloadStringAsync(
this IMyAsyncHttpService httpService, Uri address)
{
var tcs = new TaskCompletionSource<string>();
httpService.DownloadString(address, (result, exception) =>
{
if (exception != null)
tcs.TrySetException(exception);
else
tcs.TrySetResult(result);
});
return tcs.Task;
}
Now why not just do it that way:
public static async Task<string> DownloadStringAsync(
this IMyAsyncHttpService httpService, Uri address)
{
var tcs = new TaskCompletionSource<string>();
httpService.DownloadString(address, (result, exception) =>
{
if (exception != null)
tcs.TrySetException(exception);
else
tcs.TrySetResult(result);
});
return await tcs.Task;
}
Is there a functional difference between the two? Is the second one not more natural?
By marking it async, the compiler will generate warnings, that it should be considered to await this method
You don't have to mark your own method as async in order to get the "Task not awaited" warning. The following code generates the same warning for the calls to both T and U:
static async Task Main(string[] args)
{
Console.WriteLine("Done");
T();
U();
Console.WriteLine("Hello");
}
public static Task T()
{
return Task.CompletedTask;
}
public static async Task U()
{
await Task.Yield();
return;
}
Whenever you find yourself with a method only containing a single await and that being the last thing it does (except possibly returning the awaited value), you should ask yourself what value it's adding. Aside from some differences in exception handing, it's just adding an extra Task into the mix.
await is generally a way of indicating "I've got no useful work to do right now, but will have when this other Task is finished" which of course isn't true (you've got no other work to do later). So skip the await and just return what you would have awaited instead.
Your version is strictly more complex -- instead of just returning the task, you make the method async, and await the task you could just be returning.
There is one subtle practical difference (other than the version with await being slower to run).
In the first example, if DownloadString throws an exception (rather than calling the delegate you pass it with exception set), then that exception will bubble through your call to DownloadStringAsync.
In the second, the exception is packaged into the Task returned from DownloadStringAsync.
So, assuming that DownloadString throws this exception (and no other exceptions occur):
Task<string> task;
try
{
task = httpService.DownloadStringAsync(...);
}
catch (Exception e)
{
// Catches the exception ONLY in your first non-async example
}
try
{
await task;
}
catch (Exception e)
{
// Catches the exception ONLY in your second async example
}
You probably don't care about the distinction - if you just write:
await httpService.DownloadStringAsync(...);
you won't notice the difference.
Again, this only happens if the DownloadString method itself throws. If it instead calls the delegate you give it with exception set to a value, then there is no observable difference between your two cases.
Folks, thanks for the helpful comments.
In the meantime I have read the sources referenced here and also investigated the matter further: Influenced by https://blog.stephencleary.com/2016/12/eliding-async-await.html I have come to the conclusion, that its best practice to include async-await by default even in synchronous methods of the async function chain and only omit async await when the circumstances clearly indicate that the method will not potentially behave differently as expected from an async method en edge scenarios.
Such as: the synchronous method is short, simple and has no operations inside which could throw an exception. If the synchronous method throws an exception the caller will get an exception in the calling line instead of the line where the Task is awaited. This is clearly a change from expected behavior.
For example handing over call parameters to the next layer unchanged is a situation which imo permits omitting async-await.
Read my answer why returning the task is not a good idea: What is the purpose of "return await" in C#?
Basically you break your call stack if you don't use await.
Imagine this is a method performing a DB query and returning a result, which in case of null is replaced with a default value (Null object pattern).
public ResultObj Get()
{
var result = dbContext.GetSomeResult();
return result ?? ResultObj.NullValue;
}
Imagine this DB query is a long-running process, so I would use async/await to execute this process in a separate thread. Suppose that the dbContext.GetSomeResultAsync() method is available.
How can be this method converted in an asynchronous one so that I can write something like this?
var resultTask = GetAsync();
var otherResultTask = GetSomethingElseAsync();
Task.WaitAll(resultTask, otherResultTask);
var myResult = resultTask.Result;
var myOtherResult = otherResultTask.Result;
I tried this solution.
public async Task<ResultObj> GetAsync()
{
var result = await dbContext.GetSomeResultAsync();
return result ?? ResultObj.NullValue;
}
First, I'm wondering why this code compiles: why can I return ResultObj when Task<ResultObj> is expected?
Second, this code predictably results in a deadlock, as clearly explained by the great number of resources about async deadlocks anti-patterns. The deadlock can be prevented by using .ConfigureAwait(false) method after the async call. Is this the right way to go? Are there any hidden drawbacks in this case? Is it a general rule?
I also tried this.
public async Task<ResultObj> GetAsync()
{
return await Task.Run(() => {
var result = dbContext.GetSomeResult();
return result ?? ResultObj.NullValue;
});
}
This results in a deadlock, too. This time I cannot even figure out why.
Edit: possible solution
Finally, after having read this, I found a solution to my problem.
My generic query wrapper method is like this.
public async Task<ResultObj> GetAsync()
{
var result = await dbContext.GetSomeResultAsync();
return result ?? ResultObj.NullValue;
}
On calling method, I use this pattern.
public async Task<CollectedResults> CollectAsync()
{
var resultTask = GetAsync();
var otherResultTask = GetSomethingElseAsync();
//here both queries are being executed.
//...in the while, optionally, here some other synchronous actions
//then, await results
var result = await resultTask;
var otherResult = await otherResultTask;
//here process collected results and return
return new CollectedResults(...);
}
It is worth mentioning that the above code, wrapped in a domain class, is called by a Controller action. In order for this to work I had to make async the methods all the way up, until Controller action, which now appears as follows.
public async Task<CollectedResults> Get()
{
return await resultsCollector.CollectAsync();
}
This way, deadlock doesn't happen anymore and execution time greatly improves with respect to the synchronous version.
I don't know if this is the canonical way of executing parallel queries. But it works and I don't see particular pitfalls in the code.
First of all, regarding :
so I would use async/await to execute this process in a separate thread.
There is no new thread created when we use async and await
Secondly:
why can I return ResultObj when Task is expected?
the Task<TResult> as return type of method tells that it returns a Task of type TResult but we need to return object of type that TResult back from it so the method can be awaited and when using Task<TResult> as reutrn type we should be using async and await to do the work.
Lastly:
this code predictably results in a deadlock
You are using async keyword with method signatures and also await the next async method call being done from within the method. So apparently it looks like the code in first example you have posted shouldn't be deadlocked, if the method GetSomeResultAsync you are consuming is really a async method and is properly implemented.
I suggest to study more about the async await before getting in to it, following is a good article to start with:
https://blog.stephencleary.com/2012/02/async-and-await.html
As I have seen in several coding examples, as well as, what I can understand from this SO question I should be able to return a non-generic Task from TaskCompletionSource
(i.e., Return Task and not Task<TResult> from the method UploadFilesAsync)
Yet the following code:
public async Task UploadFilesAsync(string fileAPath, string fileBPath)
{
var tcs = new TaskCompletionSource<Object>();
//logic to process files
try
{
await Task.WhenAll(uploadFileAAsync(fileAPath),
uploadFileBAsync(fileBPath));
tcs.TrySetResult(null);
}
catch (Exception e)
{
tcs.SetException(e);
}
finally
{
//logic to clean up files
}
return tcs.Task;
}
Produces the following syntax error
'UploadFilesAsync(string, string)' is an async method that returns 'Task',
a return keyword must not be followed by an object expression.
Did you intend to return 'Task<T>'?
I am targeting .NET 4.5. I know it can work to return Task(of object) but that makes the API feel "dirty". Is it preferred practice to return Task(of object) or is it possible to return Task (non-generic as shown in the code)?
I know it can work to return Task(of object)
Well, that won't do what you expect it to.
The trouble is that you're trying to return a task... and an async method automatically wraps the return value in another task. It's not clear why you're using an async method at all here, to be honest. Why not just write this:
public Task UploadFilesAsync(string fileAPath, string fileBPath)
{
return Task.WhenAll(uploadFileAAsync(fileAPath), uploadFileBAsync(fileBPath));
}
Does that not do what you want? You just want a task which completes when both of the "suboperations" have completed, right? That's exactly what Task.WhenAll returns. Your method is still non-blocking - it won't wait until the operations have completed before it returns. It's just that you're using the fact that Task.WhenAll is non-blocking to achieve that, instead of an async method.
EDIT: Note that if you wanted to do something else in that method as well, you could make it an async method without using TaskCompletionSource yourself:
public async Task UploadFilesAsync(string fileAPath, string fileBPath)
{
// Upload the files
await Task.WhenAll(uploadFileAAsync(fileAPath), uploadFileBAsync(fileBPath));
await SomethingElseAsync();
MaybeDoSomethingCheap();
}
Note that even though the async method here returns Task, you don't have a return value - the async/await machinery handles all of that for you, returning a task which will complete when MaybeDoSomethingCheap() has finished, or fault if an exception is thrown.
As far as I know there is no direct way to return a Task object when employing TaskCompletionSource<T>.
Generally I prefer to return a Task<bool> type object at these situations. But you are right that, returning a generic type object makes no sense if return values of the function is not usable.
But in fact you do not need to create a TaskCompletionSource since you have an await keyword inside the function. TaskCompletionSource is generally used to convert an synchronous function to an asynchronous one. Since you are already calling an asynchronous function (and in fact this seems as the only functionality) you do not need to create a TaskCompletionSource.
public async Task UploadFilesAsync(string fileAPath, string fileBPath)
{
return await Task.WhenAll(uploadFileAAsync(fileAPath), uploadFileBAsync(fileBPath));
}