Can we turn async methods into expression body? - c#

I was reading this article about Expression Bodied Members in C# 6.0, the author demonstrated this code:
public async Task<string> ReadFromWeb() => await RunWebRequest();
He says that it's not recommended to use async and await keywords in above code:
The compiler is performing some heavy lifting to implement the async
state machine for this method. Because of the structure of the method,
that extra work isn't really accomplishing much. It's creating a state
machine to wrap a task that simply unwraps a task returned from a
different method.
He proposed that we should write the code without async and await:
public Task<string> ReadFromWebSimple() => RunWebRequest();
I'd like to know more information about that.

Lets see what the author was talking about. When you mark a method as async, the compiler generates a state-machine on your behalf in order to allow the asynchronous style of execution to "feel like" it's executing synchronously.
When you write:
public async Task<string> ReadFromWeb() => await RunWebRequest();
The compiler generates:
[AsyncStateMachine(typeof(C.<RunWebRequest>d__1))]
public Task<string> RunWebRequest()
{
C.<RunWebRequest>d__1 <RunWebRequest>d__;
<RunWebRequest>d__.<>t__builder = AsyncTaskMethodBuilder<string>.Create();
<RunWebRequest>d__.<>1__state = -1;
AsyncTaskMethodBuilder<string> <>t__builder = <RunWebRequest>d__.<>t__builder;
<>t__builder.Start<C.<RunWebRequest>d__1>(ref <RunWebRequest>d__);
return <RunWebRequest>d__.<>t__builder.Task;
}
Since you're using an Expression Bodied Method, you actually have a single liner of a method. When do you generally await on something? when you want to manipulate the return value of the async method. With one-liners, that's never the case. This means that you can save the state-machine generation at the invocation level, and let only those who want to acutally await the result higher up the caller stack to await on your method. This will effectively transform your method to look like this:
public Task<string> ReadFromWeb()
{
return this.RunWebRequest();
}
Which saves you the rather already slim state-machine struct allocated by the compiler, which is actually quite redundant when you're creating an EBM.

Making a method async allows you to use await inside it. You don't really need await as you're not using the return value and you're not doing anything after that operation completes. In this case you can just return the task directly instead. That way your caller awaits the inner async method without the overhead of the method in between.
This avoids the work being done to make ReadFromWeb an async method. It's not a huge deal but in this case where all you have is a single invocation doing that is pretty harmless.

Related

Async Task gives warning, (without) Async Task gives error

This is probably a more of a finesse question but I have the following method inside a ViewComponent class
public async Task<IViewComponentResult> InvokeAsync()
{
return View();
}
but the name InvokeAsync is underlined and gives the following warning
This async method lacks 'await' operators and will run synchronously.
Consider using the 'await' operator to await non-blocking API calls,
or 'await Task.Run(...)' to do CPU-bound work on a background thread
but if I try removing the async from the method then return View() is underlined with red and outputs the following error
'Microsoft.AspNetCore.Mvc.ViewComponents.ViewViewComponentResult' to
'System.Threading.Tasks.Task' MVCStateManagement
So my question is what approach should I take? Let the async there indiferently of the warning, or is there a workaround / fix for this warning? Does it have that much of an impact on my project?
Thanks!
It's unclear why the method was defined as an async method that returns a Task<IViewComponentResult> in the first place.
Since the method seems to be truly synchronous and simply returns a view, you should probably define it like this:
public IViewComponentResult Invoke()
{
return View();
}
A synchronous method doesn't magically become asynchronous just because you add the async keyword to it.
If you are implementing an interface and cannot change the signature of the method, you could use the Task.FromResult method to return an already completed task (you should still remove the async keyword):
public Task<IViewComponentResult> InvokeAsync()
{
return Task.FromResult<IViewComponentResult>(View());
}
The method runs on a Task of ViewcomponentResult.
You can call it without async by using this:
public Task<IViewComponentResult> InvokeAsync()
{
return Task.FromResult<IViewComponentResult>(View());
}
Your warning will no longer show and your code will run.
You could also leave it. Either will have no impact on the performance of your project.
You have to remove the async flag and the Task<>. Just return a IViewComponentResult.
You will tipically return a object wrapped into Task<> when you do async work. If you don´t it does not make any sense.
From MSDN:
The Task class represents a single operation that returns a
value and that usually executes asynchronously. Task objects
are one of the central components of the task-based asynchronous
pattern first introduced in the .NET Framework 4. Because the work
performed by a Task object typically executes asynchronously
on a thread pool thread rather than synchronously on the main
application thread, you can use the Status property, as well as the
IsCanceled, IsCompleted, and IsFaulted properties, to determine the
state of a task. Most commonly, a lambda expression is used to specify
the work that the task is to perform.
https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task-1?view=netframework-4.7.2
EDIT:
You can also try returning:
return Task.FromResult<IViewComponentResult>(View());

Why return await Task.FromResult(true); instead of just return true?

When you create a Xamarin Forms Master-Detail sample with VS2017 you get a MockDataStore class generated with methods such as
public async Task<bool> DeleteItemAsync(string id)
{
var _item = items.Where((Item arg) => arg.Id == id).FirstOrDefault();
items.Remove(_item);
return await Task.FromResult(true);
}
It feels naive to say This is a Microsoft example therefore it must be right.
I don't understand why those methods don't just return true and I've not seen this idiom explained. Is there something subtle I"m missing here, or is this a historic workaround that should have been cleaned up from the templates?
I suppose the reasoning behind this was to prevent "async method lacks await operator" compiler warning. Authors of this autogenerated code wanted to mark function async, because that's what you will do anyway when you implement real functionality. So to prevent compiler warning (no autogenerated code should generate compiler warnings) you need to await something, and there is nothing to await in their code, so they've chosen to await Task.FromResult.
Of course when you write code yourself and not autogenerate it for future edits - you don't need to do this.
TL;DR: When a function returns Task or Task<T> it will be handled asynchronously. But it itself doesn't need to be async.
Using async…await means the compiler builds a state machine to handle this. But if the only thing that you await is the last expression you can avoid this state machine:
public Task<bool> DeleteItemAsync(string id)
{
// Nothing awaitable here...
return Task.FromResult(true);
}
and create a function that runs synchronously – but has the signature and behaviour of an asynchronous function because of the call it makes to something that acts asynchronously.
Why return Task<T>: because that's what the caller is expecting: this cannot be changed without changing all callers, and their callers, and their callers, … all the way down (probably).
So the signature cannot be changed. You have to return something waitable. But you can just return the "waitability" of another result if that's the last thing you do (a bit like achieving tail-recursion).
you get a MockDataStore
So this is only for testing: the overhead is unlikely to be significant and it gives code that can be adapted as a good example of what real code will look like. (Better than much – very poor – scaffolded code which provides a bad example.)
Note: with C#7 this would be a good case to make use of ValueTask<T> to avoid the overhead of allocating a Task<T> when the result is known immediately.
This method might (should) as well be implemented synchronously as it is indeed truly synchronous:
public bool DeleteItem(string id)
{
var _item = items.Where((Item arg) => arg.Id == id).FirstOrDefault();
items.Remove(_item);
return true;
}
It makes no sense for a synchronous method to be named *Async and return a Task<T>.
I guess you are supposed to add your own asynchronous removal logic in there. After all, the generated code is just sample code.
You would then await the actual database operation rather than Task.FromResult(true), i.e. you replace Task.FromResult(true) with an asynchronous call to a method that performs the database query and then returns true once the async method has returned successfully.

Is it useful to mark a method async when it only awaits at the return statement? [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.
Only the last line of the method below is using 'await', just before the method returns, so doesn't this mean that method is basically synchronous and should just be called "Get()" without the async modifier and the suffix Async?
public virtual async Task<TEntity> GetAsync(Guid id)
{
// some more code here
return await _dbSet.FindAsync(id);
}
doesn't this mean that method is basically synchronous
No. It's asynchronous. You're probably thinking of sequential (progressing from one thing to the next), not synchronous (blocking the current thread). An await will pause the method (sequentially) but not block the thread (asynchronously). For more information, see my async intro.
without the async modifier
While you could elide the async/await keywords, I would recommend that you do not. This is because // some more code here may throw an exception. I cover this and other considerations in my blog post on eliding async and await.
and the suffix Async?
No, that suffix is appropriate for any method that returns an awaitable (e.g., Task). So, even if you elide the async and await, it's still returning a task that should be awaited, so it should still have the Async suffix.
You can think of it this way: the Async suffix is part of the API interface. The async keyword is an implementation detail. They often go together, but not always.
Its a matter of opinion. Generally the naming convention is anything that returns Task or Task<T> has a suffix of Async.
Your example above though would be better written like this so you do not have the extra overhead of the async wrapper. This is because you do not need to await the result in that method. The consumer of the method would then await the result if it used it directly.
public virtual Task<TEntity> GetAsync(Guid id, params Expression<Func<TEntity, object>>[] includeProperties))
{
// some more code here
return _dbSet.FindAsync(id);
}
await doesn't block. It awaits asynchronously for an operation to complete. That means that the original thread is released while awaiting. In a desktop application, this means that the UI thread is released while waiting eg for an HTTP or database call to finish.
When that operation completes, execution is returned to the original thread (for desktop applications).
As it is, you can simplify your code by removing the async and await keywords and returning the Task immediatelly. The code doesn't do anything with the results of the operation, so it doesn't need to await for it to finish. This will be done by the caller of the method:
public virtual Task<TEntity> GetAsync(Guid id)
{
// some more code here
return _dbSet.FindAsync(id);
}
The real asynchronous operation in this code is FindAsync. The async keyword is just syntactic sugar that allows you to use the await keyword. If you don't need to await, you don't need the async keyword either
There are many cases where suffixing every async method with Async is simply redundant. If your method returns a Task or Task<T>, and its purpose is to get data from a database or another network resource, then of course it runs asynchronously. The compiler will also almost always give you an error if you forget to await something. With that in mind, there are some good reasons to suffix async methods with Async:
The method runs asynchronously but does not return a Task
There is an alternative other method by the same name that runs synchronously
Forgetting an await in calling code is unlikely to be caught by the compiler
Suffixing a method name with Async is meant to indicate that the method runs asynchronously, which this method does. Whether it does so using async/await or directly returns another Task is an implementation detail. Imagine you were reviewing some code calling the method that forgets to use await. Which of these makes the error more apparent?
var item1 = _example.Get(itemId1);
var item2 = _example.GetAsync(itemId2);
Based on nothing else, there's no reason to believe there's anything wrong with the first line. The second line will at least raise some eyebrows.

Does async really enable callers to await?

MSDN says:
If you specify that a method is an async method by using an Async or async modifier, you enable the following two capabilities... The marked async method can itself be awaited by methods that call it.
But another page gives this example:
private async Task SumPageSizesAsync()
{
// To use the HttpClient type in desktop apps, you must include a using directive and add a
// reference for the System.Net.Http namespace.
HttpClient client = new HttpClient();
// . . .
Task<byte[]> getContentsTask = client.GetByteArrayAsync(url);
byte[] urlContents = await getContentsTask;
// Equivalently, now that you see how it works, you can write the same thing in a single line.
//byte[] urlContents = await client.GetByteArrayAsync(url);
// . . .
}
Here we see it call a function GetByteArrayAsync which is not equipped with the async keyword, and yet the caller is able to await on the result.
Is MSDN wrong when it says that the async modifier enables callers to await?
From the caller's perspective, what's the difference between a function that returns Task<T>, and the same function marked as async?
Is MSDN wrong when it says that the async modifier enables callers to await?
No. It does allow callers to await as it rewrites your method to return a Task/Task<T>. But it isn't the only way to do so. Any method that returns an awaitable (e.g. Task<bool>, YieldAwaitable) enables the callers to await.
From the caller's perspective, what's the difference between a function that returns Task<T>, and the same function marked as async?
If it's implemented correctly, there shouldn't be any difference. The async and await keywords are a way for the compiler to help you write asynchronous code. But they are not necessary. You can (and you always could have) write asynchronous code without them.
Take Task.Delay for example. It creates a task, sets a timer, configures the timer to complete the task after some time and returns the task. It doesn't use async-await and it doesn't need to. But by returning a task it allows the caller to await it.
In fact, a lot of the task-returning methods in the .NET framework don't use async-await internally as they are the "root" asynchronous methods. They return a task but don't have a task to await themselves.
Do do not await a function, you await a Task or a Task<T> that a function returns1. In any examples where you see await client.GetByteArrayAsync(url) there is a hidden implicit Task<byte[]> that gets "passed" between the client.GetByteArrayAsync(url) and the await.
You question is similar to asking "How does the + work when you do
int result = 1 + 2;
vs when you do
int two = 2;
int result = 1 + two;
The documentation states it is for adding two numbers together, but I am not adding two numbers in the 2nd example I am adding a number and a variable."
1: It is a little more completed than that, but for 99% of the time just think of it that way.
From async/await faq (emphasis mine):
What does the “async” keyword do when applied to a method?
When you mark a method with the “async” keyword, you’re really telling
the compiler two things:
You’re telling the compiler that you want to be able to use the “await” keyword inside the method (you can use the await keyword if
and only if the method or lambda it’s in is marked as async). In doing
so, you’re telling the compiler to compile the method using a state
machine, such that the method will be able to suspend and then resume
asynchronously at await points.
You’re telling the compiler to “lift” the result of the method or any exceptions that may occur into the return type. For a method that
returns Task or Task, this means that any returned value or
exception that goes unhandled within the method is stored into the
result task. For a method that returns void, this means that any
exceptions are propagated to the caller’s context via whatever
“SynchronizationContext” was current at the time of the method’s
initial invocation.
So, think of it as a syntactic sugar over plain old asynchronous .NET model: more compiler checks, less code, and completely indifferent from the caller perspective (caller either awaits the result inside async method or uses other TPL primitives, or even blocks).
Actually, if you check the source code of the GetByteArrayAsync method, it is simply a wrapper over GetContentAsync method constructing the resulting Task with TaskCompletionSource and continuation-passing style.
private Task<T> GetContentAsync<T>(Uri requestUri, HttpCompletionOption completionOption, T defaultValue,
Func<HttpContent, Task<T>> readAs)
{
TaskCompletionSource<T> tcs = new TaskCompletionSource<T>();
GetAsync(requestUri, completionOption).ContinueWithStandard(requestTask =>
{
if (HandleRequestFaultsAndCancelation(requestTask, tcs))
{
return;
}
HttpResponseMessage response = requestTask.Result;
if (response.Content == null)
{
tcs.TrySetResult(defaultValue);
return;
}
try
{
readAs(response.Content).ContinueWithStandard(contentTask =>
{
if (!HttpUtilities.HandleFaultsAndCancelation(contentTask, tcs))
{
tcs.TrySetResult(contentTask.Result);
}
});
}
catch (Exception ex)
{
tcs.TrySetException(ex);
}
});
return tcs.Task;
}
An async modifier allows you to use the await keyword within that method. Any Task can be awaited within a method marked async -- the Task represents an ongoing activity that may or may not already be complete when it is returned to the caller.
As far as I can tell it's not being awaited. The Task is.
The marked async method can itself be awaited - that's for methods. A Task doesn't need that in order to be awaitable (which is what you're doing in await getContentsTask).
This also answers part 2 - The difference is that the one that returns Task and is not marked async cannot be awaited. Which is what MSDN says in the quoted text.
(I might be wrong, of course.)

Asynchronous method that does nothing

I have an interface IAnimation which exposes a method BeginAsync(). That method should start the animation and return when it is completed.
What I would like to do is implement a null animation class NoAnimation that just returns when it executes BeginAsync().
Is this the right implementation?
public async Task BeginAsync()
{
await Task.Run(() => { });
}
I suspect that there is a more elegant approach than this. I also considered
creating an empty method. But that gives me a warning which I don't like either.
Just use Task.CompletedTask to return a completed task:
public Task BeginAsync()
{
return Task.CompletedTask;
}
If you have a Task<TResult> use Task.FromResult<TResult> to return a completed task with a result:
public Task<bool> BeginAsync()
{
return Task.FromResult(true);
}
Your current implementation is very inefficient, as it builds the state machine, and also uses a ThreadPool thread to run the empty task.
I appreciate this doesn't exactly answer the original question (or at least not in a way that isn't already in another answer). What it does it provide additional context for #ReedCopsey's answer, for those (including me! and others, based on the comments on that answer) who initially might find it hard to understand what is going on here.
It's very easy to fall into the trap of thinking that async must be part of the signature of any asynchronous method. It looks as if it must be; it (misleadingly!) reads as if it's whole purpose is to mark a method as asynchronous.
But it's not, Task or Task<T> are required, but not async. This is shown in #ReedCopsey's answer and in the following correct example (slightly adapted from this useful SO answer):
public Task<int> MethodTaskAsync(int arg0, int arg1)
{
Task<int> task = new Task<int>(() => Method(arg0, arg1));
task.Start(); // Hot task (started task) should always be returned.
return task;
}
That's why interface method signatures don't need, and can't have, the async keyword: an 'asynchronous' method per se, without regard to how it might be implemented, is just a method that returns a started (and, possibly, already finished) Task or Task<T>.
If async doesn't mark a method as asynchronous, what does it do? It's a way to write asynchronous methods more simply: once you have applied it to a method, you can use the await keyword to tell the compiler to correctly handle subsidiary asynchronous calls for you very simply (without it, you could try to handle subsidiary Tasks manually, using lots more code like that in the code block above, but to do so would be very complex and error prone).
So if you just want to return a do-nothing, already-completed task from an 'asynchronous' (i.e. Task-returning) method, you can and should do so synchronously(!), as in #ReedCopsey 's answers, using Task.CompletedTask or Task.FromResult(...).

Categories

Resources