Can calling await in the same line as the async method be slower than calling normal method?
From what I know asynchronous methods are good for I/O operations like getting data from the database. But what if there is nothing to do between calling the async method and awaiting it I need to do it in the same line.
In this post Await and Async in the same line they discussed that the benefit comes from freeing thread.
I have some unit tests for testing my services and methods using async methods as I described are always taking longer than their non-async equivalents. I assume it's because creating work in a separate thread and then awaiting it has some price.
So what I want to ask is, if using async in this case has truly some benefits.
public async Task AssignHighestRank(User user)
{
user.Rank = await _rankRepository.GetHighestRank();
_userRepository.Update(user);
await _userRepository.SaveChanges();
}
async implementation uses additional CPU cycles, so in this sense an async method would be slightly slower than its equivalent that is not asynchronous. However, using such method together with other async methods may improve performance.
For example, consider a situation when you need to make multiple changes at once:
public async Task RecordBattleResultAsync(User winner, User loser) {
await Task.WhenAll(
AssignHighestRankAsync(winner)
, AssignLowestRankAsync(loser)
).ConfigureAwait(false);
}
This method would exploit the fact that both your methods are async for a potential speed-up.
Based on this investigation async method works slowly with consistently operations then regular one does the same (if we do not regard that async methods does not hold execution thread unlike regular one) :
Should I worry about "This async method lacks 'await' operators and will run synchronously" warning
due to huge amount of compiler's works under the hood. But using operation Task.WhenAll (creation task that is completed when all task are completed too - main thread is not blocked) and Task.WaitAll (almost the same save for main thread is blocked) with independence data task might increase speed-up of method execution (methods but not whole application in case Task.WaitAll) because of parallel task execution .
Related
This question already has answers here:
When does 'await' immediately leave a method and when does it not?
(6 answers)
Closed 9 months ago.
After reading a lot about async/await I still have a fundamental question (that I kind of assume the answer but I just want confirmation).
Let's discuss over some code:
async Task methodA() {
//code A (without awaits or Task.Run)
Task.Run(()=> //code A' (without awaits or Task.Run))
}
async Task methodB() {
//code B (without awaits or Task.Run)
await methodA();
}
void Main() {
//code C (without awaits or Task.Run)
methodB(); (no await)
//code D (without awaits or Task.Run, no pun intended)
}
What I think will happen:
Run code C
Run code B
Run code A
Run code A' and code D (different threads, in parallel)
The doubt comes from what's in the documentation:
The await operator suspends evaluation of the enclosing async method
until the asynchronous operation represented by its operand completes. [...]
The await operator doesn't block the thread that evaluates the async method.
The key being here what represents an asynchronous operation. Cause considering this other piece of documentation:
The await operator tells the compiler that the async method can't
continue past that point until the awaited asynchronous process is
complete. In the meantime, control returns to the caller of the async
method.
One might think that, since methodA() is async, once methodB reaches the await methodA(), then it might return control to the caller and allow to run code D in parallel to code A and code A'.
The essence is if method A constitutes an asynchronous operation as described in the documentation, or only until it reaches truly async code (code that runs on another thread) then it actually allows control to return to the caller (which in this case is code A').
My understanding is that asynchronous operation is an operation that will run on another thread, is this correct? So things like Task.Run, Task.Delay, Task.Sleep..? And that even though code A is within an async method, it is not an async operation and control does not go immediately back when awaiting methodA. Is this correct?
Just for completion, check this question where in the answer's comments they argue precisely about this, without a very clear answer.
[...], control returns to the caller of the async method.
This sentence had confused the hell out of me when I was learning asynchronous programming. What it means is that the Task is created and returned. You can think the asynchronous methods as generators for Task objects. The async method has to do some work in order to create the Task. This work completes when the first await of an incomplete awaitable inside the method is reached. At that point the Task is created, it is handed to the caller of the method, and the caller can do whatever it wants with it.
Usually the caller awaits the task, but it can also do other things before awaiting it, or it might never await it and completely ignore it, although this is not recommended. Generally you want to keep track of your tasks, and not let them run unattended in a fire-and-forget fashion.
When the caller does not await immediately the returned task, and the task was not in a completed state upon creation, you introduce concurrency in your application: More than one things might be happening at overlapping time spans. You can read about the differences between concurrency and parallelism here.
In this example,
private async void Button1_Click(object sender, EventArgs e)
{
if (condition) await Task.Run(Foo);
}
private void Foo()
{
Thread.Sleep(5000);
}
sometimes condition is false, and the async method awaits nothing. But consider this example,
private async void Button1_Click(object sender, EventArgs e)
{
await Task.Run(Foo);
}
private void Foo()
{
if (condition) Thread.Sleep(5000);
}
where the method is always awaited, even if condition is false. I'm wondering what happens behind the scenes, if one is more preferable to the other, I mean objectively if there are compiler optimizations which make one preferable over the other. Assume condition can be checked from any thread, and has a very minimal impact to performance.
It seems that when the condition check is deferred, there is always a task being awaited, but when it's false in the handler, I have a situation which is close to one where the async method lacks an await operator, about which the compiler warns me. So it feels both wrong and right at the same time. Hoping someone can shed some objective light on this question.
Should async method always call await, if not what is the implication?
As I describe on my blog, async methods always begin executing synchronously, just like any other methods. await is where things may get asynchronous.
If a code path is taken where there is no await (or if the tasks awaited are already completed), then the method completes synchronously and returns an already-completed task to its caller. This is not a problem in practice, because "*Async" means "may be asynchronous", not "must be asynchronous".
In this specific example, you're using async void, but if this was an async Task method that was called a lot, in that case I'd recommend considering returning ValueTask instead, which would save some memory allocation for the Task whenever it completes synchronously.
The async keyword on the method is mearly an indicator to the compiler that the code inside the method should be converted into a state-machine with state transitions at the awaits.
The only technical down-side, that I am aware of, to having an async method that doesn't await anything, is the small amount of overhead introduced by the state-machine. It should have no negative effects, other than a very small performance impact, and a tiny bit of memory-pressure, that can most likely be ignored in your scenario.
In your particular case Thread.Sleep(5000) is not the best way of pausing the execution. Thread.Sleep(5000) is an old API and it blocks the execution thread for a given time (5000ms). What does that mean? It means the thread won't be available for other tasks. Let's say, given your computer CPU output, you have 4 threads in total and you lock 1 of them for 5000ms - it is really bad especially if it is a web application that has to handle concurrent API requests. What to use instead? await Task.Delay(5000) it will "hang" the execution for a given time, yet the thread is going to come back to the thread pool and will be available for other tasks.
Now closer to your question. Wrapping non-asynchronous code into Task and awaiting won't do anything. Async/await was designed for I/O operations specifically for not blocking threads that are waiting for I/O to complete. Wrapping code into Task and not awaiting - is basically "fire and forget" which means your execution thread may continue to execute the next block without waiting for your Task method to complete. Why I say may is because if your code wrapper in Task is fast enough it would work synchronously
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.
What would be an appropriate way to re-write my SlowMethodAsync async method, which executes a long running task, that can be awaited, but without using Task.Run?
I can do it with Task.Run as following:
public async Task SlowMethodAsync()
{
await Task.Run(() => SlowMethod());
}
public void SlowMethod()
{
//heavy math calculation process takes place here
}
The code, as it shown above, will spawn a new thread from a thread-pool. If it can be done differently, will it run on the invocation thread, and block it any way, as the SlowMethod content is a solid chunk of math processing without any sort of yielding and time-slice surrendering.
Just to clarify that I need my method to stay asynchronous, as it unblocks my UI thread. Just looking for another possible way to do that in a different way to how it's currently done, while keeping async method signature.
async methods are meant for asynchronous operations. They enable not blocking threads for non-CPU-bound work. If your SlowMethod has any IO-bound operations which are currently executed synchronously (e.g. Stream.Read or Socket.Send) you can exchange these for async ones and await them in your async method.
In your case (math processing) the code's probably mostly CPU-bound, so other than offloading the work to a ThreadPool thread (using Task.Run) there's no reason to use async as all. Keep SlowMethod as it is and it will run on the calling thread.
Regarding your update: You definitely want to use Task.Run (or one of the Task.Factory.StartNew overloads) to offload your work to a different thread.
Actually, for your specific case, you should use
await Task.Factory.StartNew(() => SlowMethod(), TaskCreationOptions.LongRunning)
which will allow the scheduler to run your synchronous task in the appropriate place (probably in a new thread) so it doesn't gum up the ThreadPool (which isn't really designed for CPU heavy workloads).
Wouldn't it be better just to call SlowMethod synchronously? What are you gaining by awaiting it?
The async-await features make it elegant to write non-blocking code. But, while non blocking, the work performed within an async function can still be non-trivial.
When writing async code, I find it natural to write code that follows the pattern 'all the way down the rabbit hole', so to speak, where all methods within the calling tree are marked async and the APIs used are async; but even while non blocking, the executed code can take up a fair amount of the contextual thread's time.
How and when do you decide to run an async-able method concurrently on top of asynchronously? Should one err on having the new Task created higher or lower in the call tree? Are there any best practices for this type of 'optimization'?
I've been using async in production for a couple of years. There are a few core "best practices" that I recommend:
Don't block on async code. Use async "all the way down". (Corollary: prefer async Task to async void unless you have to use async void).
Use ConfigureAwait(false) wherever possible in your "library" methods.
You've already figured out the "async all the way down" part, and you're at the point that ConfigureAwait(false) becomes useful.
Say you have an async method A that calls another async method B. A updates the UI with the results of B, but B doesn't depend on the UI. So we have:
async Task A()
{
var result = await B();
myUIElement.Text = result;
}
async Task<string> B()
{
var rawString = await SomeOtherStuff();
var result = DoProcessingOnRawString(rawString);
return result;
}
In this example, I would call B a "library" method since it doesn't really need to run in the UI context. Right now, B does run in the UI thread, so DoProcessingOnRawString is causing responsiveness issues.
So, add a ConfigureAwait(false) to every await in B:
async Task<string> B()
{
var rawString = await SomeOtherStuff().ConfigureAwait(false);
var result = DoProcessingOnRawString(rawString);
return result;
}
Now, when B resumes after awaiting SomeOtherStuff (assuming it did actually have to await), it will resume on a thread pool thread instead of the UI context. When B completes, even though it's running on the thread pool, A will resume on the UI context.
You can't add ConfigureAwait(false) to A because A depends on the UI context.
You also have the option of explicitly queueing tasks to the thread pool (await Task.Run(..)), and you should do this if you have particular CPU-intensive functionality. But if your performance is suffering from "thousands of paper cuts", you can use ConfigureAwait(false) to offload a lot of the async "housekeeping" onto the thread pool.
You may find my intro post helpful (it goes into more of the "why's"), and the async FAQ also has lots of great references.
Async-await does not actually use threads in the current .NET process-space. it is designed for "blocking" IO and network operations, like database calls, web requests, some file IO.
I cannot perceive what advantage there would be in C# to what you call the rabbit-hole technique. Doing so only obscures the code and unnecessarily couples your potentially high-cpu code to your IO code.
To answer your question directly, I would only use async-await for the aforementioned IO/network scenarios, right at the point where you are doing the blocking operations, and for anything that was CPU bound I would use threading techniques to make the best use of the available CPU cores. No need to mix the two concerns.