Task.Run() vs Async/Await - c#

I have a question regarding some code I am writing. I have 3 calls made synchronously to some endpoints that have large payloads. I don’t want to wait for these payloads and instead continue running through the method until I need the values from those 3 endpoints.
I have approached a solution like this. I converted the method that calls the 3 service endpoints into an async method. I start the call for the data using
var serviceCallOneTask = Task.Run(()=> serviceCallOne());
Note serviceCallOne() is not asynchronous
and finally when I need the data I do something like
var serviceCallOneValue = await serviceCallOneTask;
My questions are
Is this solution considered bad practice?
Should I be worried about deadlocks?
From what I have read, when using await we are not blocking a thread but when using task.run we are using a CPU-bound thread and we are blocking the thread pool; is that correct?
Is it better for me to convert everything in this httpGet method from beginning to end into async methods?
Is it ok for me to approach the problem this way for now and later on convert those task.run() services into asynchronous methods?

Is this solution considered bad practice?
It depends what you're doing.
Task.Run moves execution to another thread. That is helpful in a desktop application because you don't want long-running CPU-bound operations running on the UI thread and locking up your UI.
ASP.NET is different since there is no UI thread, so there is no need to move operations to another thread, unless you want to do something in parallel (run two CPU-bound operations at the same time).
If you're doing something else between calling Task.Run and await serviceCallOneTask, then that's certainly a reason to do what you're doing. But whether it's "better" depends on what serviceCallOne() is doing. You have to think about two things to determine if the benefit outweighs the cost:
Does the benefit of running it in a separate thread outweigh the cost of moving it to a separate thread? (Is it actually faster than running it in the same thread?)
Remember that ASP.NET has a limited number of threads (by default, 20 per processor), and now you're using 2 threads instead of 1. Depending on the expected load of your application, that may or may not matter.
Should I be worried about deadlocks?
Not with the small bit of code that you've shown. As long as you don't wait synchronously on an async method, you will not have to worry about deadlocks.
From what I have read, when using await we are not blocking a thread but when using task.run we are using a CPU-bound thread and we are blocking the thread pool; is that correct?
When using await, you don't block the current thread. As discussed above, you might just be blocking another thread, depending on your code.
Is it better for me to convert everything in this httpGet method from beginning to end into async methods?
Considering the limited thread that ASP.NET has, and that async/await helps you free up threads, then yes. It's always better to use async wherever you can.
Is it ok for me to approach the problem this way for now and later on convert those task.run() services into asynchronous methods?
If it works, then it's "ok". But you have to change something, right? May as well do it right. :)

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!).

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.

Why Use Async/Await Over Normal Threading or Tasks?

I've been reading a lot about async and await, and at first I didn't get it because I didn't properly understand threading or tasks. But after getting to grips with both I wonder: why use async/await if you're comfortable with threads?
The asynchronousy of async/await can be done with Thread signaling, or Thread.Join() etc. Is it merely for time saving coding and "less" hassle?
Yes, it is a syntactic sugar that makes dealing with threads much easier, it also makes the code easier to maintain, because the thread management is done by run-time. await release the thread immediately and allows that thread or another one to pick up where it left off, even if done on the main thread.
Like other abstractions, if you want complete control over the mechanisms under the covers, then you are still free to implement similar logic using thread signaling, etc.
If you are interested in seeing what async/await produces then you can use Reflector or ILSpy to decompile the generated code.
Read What does async & await generate? for a description of what C# 5.0 is doing on your behalf.
If await was just calling Task.Wait we wouldn't need special syntax and new APIs for that. The major difference is that async/await releases the current thread completely while waiting for completion. During an async IO there is no thread involved at all. The IO is just a small data structure inside of the kernel.
async/await uses callback-based waiting under the hood and makes all its nastiness (think of JavaScript callbacks...) go a way.
Note, that async does not just move the work to a background thread (in general). It releases all threads involved.
Comparing async and await with threads is like comparing apples and pipe wrenches. From 10,000 feet they may look similar, but they are very different solutions to very different problems.
async and await are all about asynchronous programming; specifically, allowing a method to pause itself while it's waiting for some operation. When the method pauses, it returns to its caller (usually returning a task, which is completed when the method completes).
I assume you're familiar with threading, which is about managing threads. The closest parallel to a thread in the async world is Task.Run, which starts executing some code on a background thread and returns a task which is completed when that code completes.
async and await were carefully designed to be thread-agnostic. So they work quite well in the UI thread of WPF/Win8/WinForms/Silverlight/WP apps, keeping the UI thread responsive without tying up thread pool resources. They also work quite well in multithreaded scenarios such as ASP.NET.
If you're looking for a good intro to async/await, I wrote up one on my blog which has links to additional recommended reading.
There is a difference between the Threads and async/await feature.
Think about a situation, where you are calling a network to get some data from network. Here the Thread which is calling the Network Driver (probably running in some svchost process) keeps itself blocked, and consumes resources.
In case of Async/await, if the call is not network bound, it wraps the entire call into a callback using SynchronizationContext which is capable of getting callback from external process. This frees the Thread and the Thread will be available for other things to consume.
Asynchrony and Concurrency are two different thing, the former is just calling something in async mode while the later is really cpu bound. Threads are generally better when you need concurrency.
I have written a blog long ago describing these features .
C# 5.0 vNext - New Asynchronous Pattern
async/await does not use threads; that's one of the big advantages. It keeps your application responsive without the added complexity and overhead inherent in threads.
The purpose is to make it easy to keep an application responsive when dealing with long-running, I/O intensive operations. For example, it's great if you have to download a bunch of data from a web site, or read files from disk. Spinning up a new thread (or threads) is overkill in those cases.
The general rule is to use threads via Task.Run when dealing with CPU-bound operations, and async/await when dealing with I/O bound operations.
Stephen Toub has a great blog post on async/await that I recommend you read.

Scheduling of I/O-bound operations in .NET

If I'm on a thread which doesn't need to be responsive, and for which continued execution relies on the result of an I/O bound call (HttpClient request), is there any value in implementing the call asynchronously in .NET?
Will Windows know that I'm waiting on an I/O operation and refrain from scheduling the thread until data arrives?
I recall reading somewhere that it does, but I'm afraid I still have difficulty understanding how this works and when I can rely on it.
No, there is no value in using async there. As you suspect, Windows will know that the thread is waiting for IO and won't schedule the thread until the data arrives.
However, the idea of async is that you don't really need to create a new thread. The idea of async is that (I'm cutting a few corners here; there is better documentation available on the Internet) it tries to do something like you're doing here manually. So instead of you having to create a new thread, async does this for you. (It doesn't actually create a new thread, but you get the idea.)
If this needs to be high performance, I would not advise to do it the way you're implementing it now. Async would be much better for this. In your case, when you're doing 1000 requests, you would have 1000 threads, which is not a good idea. Async would accomplish this a lot smarter, and will give you better performance.
The basic advantage of using async (besides performance) is that it's like you're actually programming only on the UI thread. Previously, that would have locked up your application, but with async your application stays responsive. That's really the primary advantage of async.

Async methods don't require additional threads?

In MSDN, there is a paragraph like this:
The async and await keywords don't cause additional threads to be
created. Async methods don't require multithreading because an async
method doesn't run on its own thread. The method runs on the current
synchronization context and uses time on the thread only when the
method is active. You can use Task.Run to move CPU-bound work to a
background thread, but a background thread doesn't help with a process
that's just waiting for results to become available.
But it looks I need little more help with the bold text since I am not sure what it exactly means. So how come it becomes async without using Threads?
Source: http://msdn.microsoft.com/en-us/library/hh191443.aspx
There are many asynchronous operations which don't require the use of multiple threads. Things like Asynchronous IO work by having interrupts which signal when data is available. This allows you to have an asynchronous call which isn't using extra threads - when the signal occurs, the operation completes.
Task.Run can be used to make your own CPU-based async methods, which will run on its own separate thread. The paragraph was intended to show that this isn't the only option, however.
async/await is not just about using more threads. It's about using the threads you have more effectively. When operations block, such as waiting on a download or file read, the async/await pattern allows you to use that existing thread for something else. The compiler handles all the magic plumbing underneath, making it much easier to develop with.
See http://msdn.microsoft.com/en-us/magazine/hh456401.aspx for the problem description and the whitepaper at http://www.microsoft.com/en-us/download/details.aspx?id=14058.
Not the code generated by the async and await keyword themselves, no. They create code that runs on your the current thread, assuming it has a synchronization context. If it doesn't then you actually do get threads, but that's using the pattern for no good reason. The await expression, what you write on the right side of the await keyword causes threads to run.
But that thread is often not observable, it may be a device driver thread. Which reports that it is done with a I/O completion port. Pretty common, I/O is always a good reason to use await. If not already forced on you by WinRT, the real reason that async/await got added.
A note about "having a synchronization context". You have one on a thread if the SynchronizationContext.Current property is not null. This is almost only ever the case on the main thread of a gui app. Also the only place where you normally ever worry about having delays not freeze your user interface.
Essentially what it's doing is when you run an async method without calling it with await is this:
Start the method and do as much as possible sychronously.
When necessary, pause the method and put the rest of it into a continuation.
When the async part is completed (is no longer being waited on), schedule the continuation to run on the same thread.
Whatever you want can run on this thread as normal. You can even examine/manipulate the Task returned from the async method.
When the thread becomes available, it will run the rest of your method.
The 'async part' could be file IO, a web request, or pretty much anything, as long as calling code can wait on this task to complete. This includes, but is not limited to, a separate thread. As Reed Copsey pointed out, there are other ways of performing async operations, like interrupts.

Categories