Async and await - difference between console, Windows Forms and ASP.NET - c#

I have been educating myself on async / await use and I think I understood under-the-hood concept. However, most of Channel 9 tutorials, MSDN articles and Stack overflow answers on async / await use GUI-based applications (Windows Forms application) to demonstrate the power of async / await.
However, I noticed a fundamental difference in async / await use in a UI-thread based application vs. regular ThreadPool thread-based applications (e.g. ASP.NET Web Application, Console Application, etc.).
Since, in UI thread-based application, the UI thread is always available (unless the process is stopped explicitly or by Windows), so the ThreadPool thread responsible for executing the code after "await" in any async method, will guarantee to find the UI thread to post the results back (if any).
However, in a console application or ASP.NET Web application, the main thread (in a console application) or the HTTP request (in an ASP.NET web application) must be waiting (at one point of time) until all async operations are completed. So there should be .Wait() and .Result call somewhere after the Async method call, if there is nothing more to work on.
Is this understanding correct? I am not questioning the benefit of having async for I/O bound or network-bound operations (I understand how it's going to increase application scalability).

Since, in UI thread based application, the UI thread is always available (unless the process is stopped explicitly or by Windows), so the ThreadPool thread responsible for executing the code after "await" in any async method, will guarantee to find the UI thread to post the results back (if any).
This is slightly confused. There's no indication that a ThreadPool thread will be required at all.
It's up to the awaitable implementation to determine where to run the continuation, but normally the current synchronization context is used to work out where to run it:
In a console application, there is no synchronization context, so a thread pool thread is used for the continuation.
In a Windows Forms application, when you're running on the UI thread the synchronization context is one which will execute code on the UI thread... so the continuation executes there (unless you use ConfigureAwait, etc...)
In an ASP.NET application, there's a synchronization context specific to ASP.NET itself.
See Stephen Cleary's MSDN article for more details.
It's not clear what you mean by your later question about having to call Wait or Result in ASP.NET or a console app... in both scenarios it may be required, but equally it may not be. It depends on what you're doing really. Don't forget that even a console app can start its own threads and do all kinds of other things - you can write an HTTP server in a console app, for example...

Related

Is it bad practice to have async call within Task.Run?

I have a C# console app processing around 100,000 JSON messages from RabbitMQ every 1 min
After getting each/a bunch of messages from RabbitMQ I then call
await Task.Run(async () =>
{
//do lots of CPU stuff here, including 2 external API calls using await async call
}
Everything I've read says use await Task.Run for CPU bound operations. And use await async for the HTTP external calls.
If I change it to:
await Task.Run(() =>
Then it complains as I have an async API call in the lines below, so it needs the async keyword in the Task.Run statement.
There are about 2000+ (complex if then business rules) lines of code in this section, and the sometimes the API call is not needed.
So I'm faced with either a massive restructure of the application, with lots of testing needed, or if its ok to do API calls alongside the CPU bound operations then I'll leave it as is.
To summarise, is this bad practice, or is it ok to have CPU bound work and API calls inside the same task? The task is processing one JSON message.
Everything I've read says use await task.run for cpu bound operations . And use await async for the http external calls
The general guideline is to use async/await for I/O. Task.Run is useful for CPU-bound operations if you need to offload them from a UI thread. For example, in server scenarios such as ASP.NET, you wouldn't want to use Task.Run for CPU-bound code. This is because ASP.NET already schedules your code on a separate thread pool thread.
In your case, you have a Console application, which doesn't have a UI thread. But it also doesn't have that automatic scheduling onto a thread pool thread that ASP.NET gives you.
if its ok to do api calls alongside the cpu bound operations then i'll leave it as is.
This is fine either way. Since the code is awaiting the Task.Run, it won't continue (presumably processing the next message) until the operation completes on another thread pool thread. So the Task.Run isn't helping much, but it isn't hurting much, either.
If you need more performance - specifically, processing messages concurrently - then you should look into something like TPL Dataflow or System.Threading.Channels that would allow you to replace the Task.Run with a queue of work that can run in parallel. That would give you something more like what ASP.NET provides out of the box.
General
(...) use await Task.Run for CPU bound operations. And use await async for the HTTP external calls.
This advice comes from the fact that if you run code that doesn't 'let go' enough then you may not get a lot of the benefit Tasks give because the current thread / thread pool just cannot handle the work. In the extreme case when you run 100% synchronous code you won't get any parallelism because the current thread cannot let go and cannot do any other work - your tasks would be executed sequentially. It's important to remember that this is not a style issue; running busy synchronous code with Tasks just work well in some scenarios. In this sense the problem polices itself: if you structure the solution incorrectly it doesn't do what you need.
If you run a mixture of busy and waiting then Task.Run may or may not be great and it will depend on the specific workload. If it works for you, it's fine - you're not doing anything incorrect.
Generally the picture is nuanced and tasks can be and are used to do all kinds of jobs. In certain circumstances the situation is clear cut - e.g. if you run long running work in the UI thread you will lock the UI which is bad or if you have (long-running) busy synchronous code. It's worth keeping in mind that this has been a problem before C# had Tasks.
BTW. If you look at the reference documentation for Task.WhenAll Method it contains examples with both I/O (ping) and CPU (dummy for loop) style work. Yes, these are toy examples but it shows it isn't incorrect to run both types of work with tasks.
Parallel.ForEachAsync?
If you can use .NET 6, Parallel.ForEachAsync could improve performance of your solution and/or make the code look cleaner. Example on Twitter (as picture!).

Proper way to start and fire-and-forget asynchronous calls?

I have an async call (DoAsyncWork()), that I would like to start in a fire-and-forget way, i.e. I'm not interesting in its result and would like the calling thread to continue even before the async method is finished.
What is the proper way to do this? I need this in both, .NET Framework 4.6 as well as .NET Core 2, in case there are differences.
public async Task<MyResult> DoWorkAsync(){...}
public void StarterA(){
Task.Run(() => DoWorkAsync());
}
public void StarterB(){
Task.Run(async () => await DoWorkAsync());
}
Is it one of those two or something different/better?
//edit: Ideally without any extra libraries.
What is the proper way to do this?
First, you need to decide whether you really want fire-and-forget. In my experience, about 90% of people who ask for this actually don't want fire-and-forget; they want a background processing service.
Specifically, fire-and-forget means:
You don't care when the action completes.
You don't care if there are any exceptions when executing the action.
You don't care if the action completes at all.
So the real-world use cases for fire-and-forget are astoundingly small. An action like updating a server-side cache would be OK. Sending emails, generating documents, or anything business related is not OK, because you would (1) want the action to be completed, and (2) get notified if the action had an error.
The vast majority of the time, people don't want fire-and-forget at all; they want a background processing service. The proper way to build one of those is to add a reliable queue (e.g., Azure Queue / Amazon SQS, or even a database), and have an independent background process (e.g., Azure Function / Amazon Lambda / .NET Core BackgroundService / Win32 service) processing that queue. This is essentially what Hangfire provides (using a database for a queue, and running the background process in-proc in the ASP.NET process).
Is it one of those two or something different/better?
In the general case, there's a number of small behavior differences when eliding async and await. It's not something you would want to do "by default".
However, in this specific case - where the async lambda is only calling a single method - eliding async and await is fine.
It depends on what you mean by proper :)
For instance: are you interested in the exceptions being thrown in your "fire and forget" calls? If not, than this is sort of fine. Though what you might need to think about is in what environment the task lives.
For instance, if this is a asp.net application and you do this inside the lifetime of a thread instantiated due to a call to a .aspx or .svc. The Task becomes a background thread of that (foreground)thread. The foreground thread might get cleaned up by the application pool before your "fire and forget" task is completed.
So also think about in which thread your tasks live.
I think this article gives you some useful information on that:
https://www.hanselman.com/blog/HowToRunBackgroundTasksInASPNET.aspx
Also note that if you do not return a value in your Tasks, a task will not return exception info. Source for that is the ref book for microsoft exam 70-483
There is probably a free version of that online somewhere ;P https://www.amazon.com/Exam-Ref-70-483-Programming-C/dp/0735676828
Maybe useful to know is that if your have an async method being called by a non-async and you wish to know its result. You can use .GetAwaiter().GetResult().
Also I think it is important to note the difference between async and multi-threading.
Async is only useful if there are operations that use other parts of a computer that is not the CPU. So things like networking or I/O operations. Using async then tells the system to go ahead and use CPU power somewhere else instead of "blocking" that thread in the CPU for just waiting for a response.
multi-threading is the allocation of operations on different threads in a CPU (for instance, creating a task which creates a background thread of the foreground thread... foreground threads being the threads that make up your application, they are primary, background threads exist linked to foreground threads. If you close the linked foreground thread, the background thread closes as well)
This allows the CPU to work on different tasks at the same time.
Combining these two makes sure the CPU does not get blocked up on just 4 threads if it is a 4 thread CPU. But can open more while it waits for async tasks that are waiting for I/O operations.
I hope this gives your the information needed to do, what ever it is you are doing :)

Async/await in Web.API 2 Controllers Action [duplicate]

Background
We are currently developing a web application, which relies on ASP .NET MVC 5, Angular.JS 1.4, Web API 2 and Entity Framework 6. For scalability reasons, the web application heavility relies on the async/await pattern. Our domain requires some cpu-intensive calculations, which can takes some seconds (<10s). In the past some team members used Task.Run, in order to speed up the calculations.Since starting an extra thread inside ASP .NET MVC or Web API controllers is considered a bad practise (the thread is not known by the IIS, so not considered on AppDomain Recycle => See Stephen Cleary's blog post), they used ConfigureAwait(false).
Example
public async Task CalculateAsync(double param1, double param2)
{
// CalculateSync is synchronous and cpu-intensive (<10s)
await Task.Run(() => this.CalculateSync(param1, param2))).ConfigureAwait(false);
}
Questions
Is there any performance benefit in using Task.Run in an async Web API Controller for cpu-bound operations?
Does ConfigureAwait(false) really avoid the creation of an extra thread?
Is there any performance benefit in using Task.Run in an async Web API Controller for cpu-bound operations?
Zero. None. In fact, you're hindering performance by spawning a new thread. Within the context of a web application, spawning a thread is not the same thing as running in the "background". This is due to the nature of a web request. When there's an incoming request, a thread is taken from the pool to service the request. Using async allows the thread to be returned before the end of the request, if and only if the thread is in a wait-state, i.e. idle. Spawning a thread to do work on, effectively idles the primary thread, allowing it to be returned to the pool, but you've still got an active thread. Returning the original thread to the pool does nothing at that point. Then, when the new thread finishes its work, you've got to request a main thread back from the pool, and finally return the response. The response cannot be returned until all work has completed, so whether you use 1 thread or a hundred, async or sync, the response cannot be returned until everything finishes. Therefore, using additional threads does nothing but add overhead.
Does ConfigureAwait(false) really avoid the creation of an extra thread?
No, or more appropriately, it's not about that. ConfigureAwait is just an optimization hint, and only determines whether the original context is maintained between thread jumps. Long and short, it has nothing to do with the creation of a thread, and at least in the context of an ASP.NET application, has negligible performance impact either way.
Is there any performance benefit in using Task.Run in an async Web API Controller for cpu-bound operations?
No. And it doesn't matter whether it's CPU bound or not.
Task.Run offloads work to a ThreadPool thread. The web api request already uses a ThreadPool thread so you're just limiting scalability by offloading to another thread with no reason.
This is useful in UI apps, where the UI thread is a special single thread.
Does ConfigureAwait(false) really avoid the creation of an extra thread?
It doesn't affect thread creating in one way or another. All it does is configures whether to resume on the captured SynchronizationContext or not.
Is there any performance benefit in using Task.Run in an async Web API Controller for cpu-bound operations?
Think about what really happens - Task.Run() creates a Task on the thread pool, and your await operator will free the thread (I'm assuming all methods down the stack are also awaiting). Now your thread is back to the pool, and it might pick up that same Task! In this scenario, there is obviously no performance gain. There is performance hit, actually. But if the thread picks up another Task (that's probably what will happen), another thread would have to pick up CalculateSync() Task and continue from where the former stopped. It would have made more sense to let the original thread execute CalculateSync() in the first place, no Tasks involved, and let the other thread have the other queued Tasks.
Does ConfigureAwait(false) really avoid the creation of an extra thread?
Not at all. It merely points out that the continuation shouldn't be executed on the caller's context.
There is one more thing that you need to consider. As you told your your api is doing CPU intensive task then async/await help to run the process in another thread and free your app pool for another request. Means your web api can handle more number of request per second if you use async/await correctly.
In your case look like this.CalculateSync(param1, param2) is non-async method so to call this asynchronously you have to use Task.Run.
I'll recommend to remove .ConfigureAwait(false) as this will actually decrease your performance.

Reuse an awaiting thread

So, as everyone knows, frameworks like asp.NET, WPF and WinRT manage one or more threads for you. In asp.NET, the framework pools a set of threads that take requests from a queue and process them. In WPF, the framework manages the UI thread for you, which takes messages from the message pump.
This can be achieved with a simple producer/consumer approach, where the consuming thread executes a while(true) loop, takes messages from a queue and uses a message handler (the user's code) to execute them. Simple enough. You can find a basic implementation here: https://stackoverflow.com/a/5828863/857807
With the introduction of the async/await semantics, you can delegate CPU/IO-intensive work to some other thread, and leave the (for example) UI thread responsive. This means that the UI thread will keep taking messages from the pump.
My question is: starting with the aforementioned basic implementation, how would the consumer implement this? How would you know that the message handler is asynchronously awaiting for another thread to complete and, therefore, take another message from the queue? I'm sure I'm missing something big here.
The key is that when an async method yields in an await, it actually returns to its caller. So, from the perspective of the main loop, the method has completed.
Later on, when the awaitable operation completes, it schedules the remainder of the async method to the captured context. In the cases you mentioned (ASP.NET / WPF / WinRT), the context is a SynchronizationContext. In the UI frameworks (WPF / WinRT / WinForms / etc), that SynchronizationContext is tied to the message queue.
So if you want an async-compatible "main loop", you'd need to implement a custom SynchronizationContext that allows scheduling delegates back to that main loop.
For more information:
My async intro describes how async and await methods return and capture context.
My SynchronizationContext MSDN article describes the relevant portions of that type, and how it's used throughout the .NET framework.
My AsyncEx library has an async-compatible "main loop", including documentation, source, and unit tests.

Best practice to call ConfigureAwait for all server-side code

When you have server-side code (i.e. some ApiController) and your functions are asynchronous - so they return Task<SomeObject> - is it considered best practice that any time you await functions that you call ConfigureAwait(false)?
I had read that it is more performant since it doesn't have to switch thread contexts back to the original thread context. However, with ASP.NET Web Api, if your request is coming in on one thread, and you await some function and call ConfigureAwait(false) that could potentially put you on a different thread when you are returning the final result of your ApiController function.
I've typed up an example of what I am talking about below:
public class CustomerController : ApiController
{
public async Task<Customer> Get(int id)
{
// you are on a particular thread here
var customer = await GetCustomerAsync(id).ConfigureAwait(false);
// now you are on a different thread! will that cause problems?
return customer;
}
}
Update: ASP.NET Core does not have a SynchronizationContext. If you are on ASP.NET Core, it does not matter whether you use ConfigureAwait(false) or not.
For ASP.NET "Full" or "Classic" or whatever, the rest of this answer still applies.
Original post (for non-Core ASP.NET):
This video by the ASP.NET team has the best information on using async on ASP.NET.
I had read that it is more performant since it doesn't have to switch thread contexts back to the original thread context.
This is true with UI applications, where there is only one UI thread that you have to "sync" back to.
In ASP.NET, the situation is a bit more complex. When an async method resumes execution, it grabs a thread from the ASP.NET thread pool. If you disable the context capture using ConfigureAwait(false), then the thread just continues executing the method directly. If you do not disable the context capture, then the thread will re-enter the request context and then continue to execute the method.
So ConfigureAwait(false) does not save you a thread jump in ASP.NET; it does save you the re-entering of the request context, but this is normally very fast. ConfigureAwait(false) could be useful if you're trying to do a small amount of parallel processing of a request, but really TPL is a better fit for most of those scenarios.
However, with ASP.NET Web Api, if your request is coming in on one thread, and you await some function and call ConfigureAwait(false) that could potentially put you on a different thread when you are returning the final result of your ApiController function.
Actually, just doing an await can do that. Once your async method hits an await, the method is blocked but the thread returns to the thread pool. When the method is ready to continue, any thread is snatched from the thread pool and used to resume the method.
The only difference ConfigureAwait makes in ASP.NET is whether that thread enters the request context when resuming the method.
I have more background information in my MSDN article on SynchronizationContext and my async intro blog post.
Brief answer to your question: No. You shouldn't call ConfigureAwait(false) at the application level like that.
TL;DR version of the long answer: If you are writing a library where you don't know your consumer and don't need a synchronization context (which you shouldn't in a library I believe), you should always use ConfigureAwait(false). Otherwise, the consumers of your library may face deadlocks by consuming your asynchronous methods in a blocking fashion. This depends on the situation.
Here is a bit more detailed explanation on the importance of ConfigureAwait method (a quote from my blog post):
When you are awaiting on a method with await keyword, compiler
generates bunch of code in behalf of you. One of the purposes of this
action is to handle synchronization with the UI (or main) thread. The key
component of this feature is the SynchronizationContext.Current which
gets the synchronization context for the current thread.
SynchronizationContext.Current is populated depending on the
environment you are in. The GetAwaiter method of Task looks up for
SynchronizationContext.Current. If current synchronization context is
not null, the continuation that gets passed to that awaiter will get
posted back to that synchronization context.
When consuming a method, which uses the new asynchronous language
features, in a blocking fashion, you will end up with a deadlock if
you have an available SynchronizationContext. When you are consuming
such methods in a blocking fashion (waiting on the Task with Wait
method or taking the result directly from the Result property of the
Task), you will block the main thread at the same time. When
eventually the Task completes inside that method in the threadpool, it
is going to invoke the continuation to post back to the main thread
because SynchronizationContext.Current is available and captured. But
there is a problem here: the UI thread is blocked and you have a
deadlock!
Also, here are two great articles for you which are exactly for your question:
The Perfect Recipe to Shoot Yourself in The Foot - Ending up with a Deadlock Using the C# 5.0 Asynchronous Language Features
Asynchronous .NET Client Libraries for Your HTTP API and Awareness of async/await's Bad Effects
Finally, there is a great short video from Lucian Wischik exactly on this topic: Async library methods should consider using Task.ConfigureAwait(false).
The biggest draw back I've found with using ConfigureAwait(false) is that the thread culture is reverted to the system default. If you've configured a culture e.g ...
<system.web>
<globalization culture="en-AU" uiCulture="en-AU" />
...
and you're hosting on a server whose culture is set to en-US, then you will find before ConfigureAwait(false) is called CultureInfo.CurrentCulture will return en-AU and after you will get en-US.
i.e.
// CultureInfo.CurrentCulture ~ {en-AU}
await xxxx.ConfigureAwait(false);
// CultureInfo.CurrentCulture ~ {en-US}
If your application is doing anything which requires culture specific formatting of data, then you'll need to be mindful of this when using ConfigureAwait(false).
I have some general thoughts about the implementation of Task:
Task is disposable yet we are not supposed to use using.
ConfigureAwait was introduced in 4.5. Task was introduced in 4.0.
.NET Threads always used to flow the context (see C# via CLR book) but in the default implementation of Task.ContinueWith they do not b/c it was realised context switch is expensive and it is turned off by default.
The problem is a library developer should not care whether its clients need context flow or not hence it should not decide whether flow the context or not.
[Added later] The fact that there is no authoritative answer and proper reference and we keep fighting on this means someone has not done their job right.
I have got a few posts on the subject but my take - in addition to Tugberk's nice answer - is that you should turn all APIs asynchronous and ideally flow the context . Since you are doing async, you can simply use continuations instead of waiting so no deadlock will be cause since no wait is done in the library and you keep the flowing so the context is preserved (such as HttpContext).
Problem is when a library exposes a synchronous API but uses another asynchronous API - hence you need to use Wait()/Result in your code.

Categories