Blocking Methods within Task - c#

I'm currently developing a small server application and getting to grips with Task<>, and other associated operations.
I'm wondering how Blocking operations work within a Task.
So for example, I currently use several Libraries with "blocking" operations. One of them is Npgsql (PostgreSQL provider.)
If I do the following...
Task myTask = new Task<>( () =>
{
using(var db = new PostgresqlDatabaseConnection())
{
db.ExecuteQuery("SELECT takes 50 ms to get data...")
db.Insert(anObject); etc....
}
}
).Start();
And say, chain it to a bunch of other tasks that process that data.
Is this Efficient? I.E. Let's say that ExexuteQuery calls some kind of Thread.Sleep(1) or somehow blocks the thread, is this going to effect my Task Execution?
I'm asking because my server uses several libraries that would have to be rewritten to accomodate a totally Asynchronous methodology. Or is this Async enough?
*My Thoughts *
I'm really just not sure.
I know that if for example, the db.Executre() just ran a while(true) loop until it got it's data, it would almost certainly be blocking my server. Because a lot of time would be spend processing while(true). Or is Task smart enough to know that it should spend less time on this? Or if internally it is using some waiting mechanism, does the Task library know? Does it know that it should be processing some other task while it waits.

I'm currently developing a small server application and getting to
grips with Task<>, and other associated operations.
You won't benefit from using new Task, Task.Factory.StartNew, Task.Run in the server-side application, unless the number of concurrent client connections is really low. Check this and this for some more details.
You would however greatly benefit from using naturally asynchronous API. They don't block a pool thread while "in-flight", so the thread is returned to the pool and then can get busy serving another client request. This improves your server app scalability.
I'm not sure if PostgreSQL provides such API, look for something like ExecuteQueryAsync or BeginExecuteQuery/EndExecuteQuery. If it doesn't have that, just use the synchronous ExecuteQuery method, but do not offload it to a pool thread as you do in your code fragment.

Using the async/await features of C# 5 will definitely make things easier. It can make asynchronous code easier to write, as you write it very similar to how you would write synchronous code.
Take the following example. I am using Thread.Sleep to simulate a long running operation, so any libraries that don't support async natively can still be used via Task.Run. While the Thread.Sleep is holding up the thread, your UI is still responsive. If you had written this code synchronously, your UI would hold up for 1.5 seconds until the thread.sleep was finished.
private async void button1_Click(object sender, EventArgs e)
{
Console.WriteLine("0");
await DoWorkAsync();
Console.WriteLine("3");
}
private async Task DoWorkAsync()
{
Console.WriteLine("1");
await Task.Run(()=>
{
// Do your db work here.
Thread.Sleep(1500);
});
Console.WriteLine("2");
}
So in short, if you have a long running database operations and you want to keep your UI responsive, you should leverage async/await. While this does keep your UI responsive, it does introduce new challenges like: what happens if the user clicks a button multiple times or what if the user closes the window while you are still processing to name some simple cases.
I encourage you to read further on the subject. Jon Skeet has a multi-part series on async. There are also numerous MSDN articles on the subject: 1 2 3 ...

Async programming does nothing to improve the efficiency of your logic or of the database. All it influences it the performance of switching between operations.
You cannot make a query or a computation faster wrapping it in a Task. You only add overhead.
Async IO is used on the server to achieve scalability to hundreds of concurrent requests. You don't need it here.

Related

When you await on async call--is it really asynchronous programming in C#

I have three tier .net web api application. each tier is implementing a async method. Each call is async and and we are using await at each step. My question is when you await at every step, doesn't it make the application synchronous & defeats the purpose ? What value async await really provides? Does it automatically uses multiple CPU cores?
Controller:
public async Task<IHttpActionResult> Get()
{
return Ok(await _service.Create());
}
middle tier:
public async Task<MyObject> Create()
{
return await _repository.CreateAsync(new MyDataObject());
}
DB
public async Task<T> CreateAsync(T data)
{
var o = _dbSet.Add(data);
await _dbContext.SaveChangesAsync();
return 100;
}
In your example you're definitely doing asynchronous processing. What you're not doing is parallel processing. The .NET documentation doesn't always do a good job of differentiating between the two. I'll just cover asynchronous here.
The main idea behind async / await (which your examples do well) is to not have a thread sitting around doing nothing when it could be doing something useful.
Take your CreateAsync example:
public async Task<T> CreateAsync(T data)
{
var o = _dbSet.Add(data);
await _dbContext.SaveChangesAsync();
return 100;
}
The database changes won't happen any faster because of the await. So what's the benefit? For the sake of argument assume the following:
Your app has 5 users
Your app has 2 threads available (way low, but play along)
Each database save takes 3 seconds
Now assume User A and User B save a record at the same time. Each has their own thread (that's a fact, not an assumption). If you aren't using await then users A and B will hold both of your available threads for 3 seconds just waiting for the save to complete. No more threads are available, so users C, D and E will be blocked for that period.
When you use await, the threads are released because they're just... waiting. Now they can take care of users C, D, and E. When the save completes the threads will come back for users A and B and finish the CreateAsync method.
Bottom line, when async / await is done properly n threads can fulfill way more than n requests.
This is a simplified explanation, but I really wish I'd gotten a simple explanation way back when. I hope this helps.
What value async await really provides?
It allows your web server to process more requests at the same time; async/await allows the threads to do other work while the code waits for the db to do its work (db or cache, email service, external api call, etc.).
From Async Programming : Introduction to Async/Await on ASP.NET:
(...) let’s say the requests in the system depend on some external resource, like a database or Web API. When a request comes in, ASP.NET takes one of its thread pool threads and assigns it to that request. Because it’s written synchronously, the request handler will call that external resource synchronously. This blocks the request thread until the call to the external resource returns.
...
Asynchronous request handlers operate differently. When a request comes in, ASP.NET takes one of its thread pool threads and assigns it to that request. This time the request handler will call that external resource asynchronously. This returns the request thread to the thread pool until the call to the external resource returns.
When you await an async method in C#, it does not necessarily mean that the method is executed asynchronously. It simply means that the calling method will be suspended until the awaited task completes.
The async and await keywords in C# are used to simplify the process of writing asynchronous code. They allow you to write code that looks and reads like synchronous code, while still being asynchronous under the hood.
To understand how async and await work, it is important to know that an async method actually returns a Task or Task object, which represents the asynchronous operation. The await operator is used to suspend the execution of the calling method until the awaited Task completes.
However, just because a method is marked async does not necessarily mean that it will be executed asynchronously. The actual execution of the method depends on how the Task is implemented and whether it is running on a thread pool thread or not.
For example, if the Task is running on a ThreadPool thread, it will be executed asynchronously. On the other hand, if the Task is implemented using the Task.Run method, it will be executed synchronously on a separate ThreadPool thread.
In short, the async and await keywords in C# allow you to write asynchronous code that is easier to read and maintain, but they do not guarantee that the code will be executed asynchronously.
Each call is async and and we are using await at each step. My question is when you await at every step, doesn't it make the application synchronous & defeats the purpose?
First of all, synchronous and asynchronous is a property of a method or an execution flow, not a property of the application as a whole. In your case you await on every level and every step all asynchronous operations (Tasks) that you start, so the execution flow of each web request is asynchronous. It's still a single execution flow though. The code is executed in a sequential/serialized fashion. In the context of a single web request, no concurrency is happening.
The difference from a classic and familiar synchronous execution flow is that the flow is not forced to run on the same thread from start to finish. Different threads might be involved in the execution, but not more than one thread at the same time. A thread-switch might occur at each await point, and whether it will happen depends on various factors that might not be under your direct control. The most interesting aspect of an asynchronous flow is that, time-wise, large parts of the execution are usually not running on any thread. For example while the _dbContext.SaveChangesAsync() is doing its job, there is no thread in your process that is blocked waiting for this work to be done. This means that your web application can have a large number of concurrent executions flows (web requests), using only a small number of threads. Which eventually results in increased scalability for your application: you can serve more users with less hardware.
Relatively new developers who come to asynchronous programming directly using async/await may have this confusion. To understand and appreciate the value of what async/await brings to table, one has to go slightly back in time and review how asynchronous code was written then.
Before the keywords were introduced in C#, asynchronous programming was still possible. Traditionally (.NET Framework 2.0 later), there were two patterns:
Event-based Asynchronous Pattern (EAP), where you subscribed to an event:
o.ReadCompleted += (o, e) => { // asynchronously called after ReadAsync completion };
o.ReadAsync(buffer, count); // begin the async process
Task-based Asynchronous Pattern (TAP), which is Promise like interface where you can setup completions with then and catch.
o.ReadAsync(buffer, count)
.then( (result) => { // asynchronously called after ReadAsync completion } );
So, advantage of asynchronous programming on the server is that the calling thread is not blocked on the Read, which is now an asynchronous call as against a synchronous call. The thread can do some other tasks / or serve other requests.
When I/O bound Read eventually completes, the completion delegate will be called, possibly over a different thread. This way there are more threads available which makes the service more scalable. This is advantage of asynchronous programming.
However, the two patterns above have a disadvantage for the developer that the code becomes unreadable and inside-out because it is not written sequentially.
The async/await keywords just let us keep the same advantages of asynchronous programming, while making the code readable.
Now we just write:
var result = await o.ReadAsync(buffer, count);
// here comes code that we had to previously write inside the completion delegate
// but now its more readable, and much natural to handle exceptions
So although it looks sequential to developer it is still asynchronous. The compiler converts the async method into a state machine which behaves similar to code previously written, but hides away all the complex details from the developer. Similar to the completion delegate behavior, the code written after await could also be resumed on a different thread.

Why should I return Task<IActionResult> in a Controller?

So I have been trying to get the grasp for quite some time now but couldn't see the sense in declaring every controller-endpoint as an async method.
Let's look at a GET-Request to visualize the question.
This is my way to go with simple requests, just do the work and send the response.
[HttpGet]
public IActionResult GetUsers()
{
// Do some work and get a list of all user-objects.
List<User> userList = _dbService.ReadAllUsers();
return Ok(userList);
}
Below is the async Task<IActionResult> option I see very often, it does the same as the method above but the method itself is returning a Task. One could think, that this one is better because you can have multiple requests coming in and they get worked on asynchronously BUT I tested this approach and the approach above with the same results. Both can take multiple requests at once. So why should I choose this signature instead of the one above? I can only see the negative effects of this like transforming the code into a state-machine due to being async.
[HttpGet]
public async Task<IActionResult> GetUsers()
{
// Do some work and get a list of all user-objects.
List<User> userList = _dbService.ReadAllUsers();
return Ok(userList);
}
This approach below is also something I don't get the grasp off. I see a lot of code having exactly this setup. One async method they await and then returning the result. Awaiting like this makes the code sequential again instead of having the benefits of Multitasking/Multithreading. Am I wrong on this one?
[HttpGet]
public async Task<IActionResult> GetUsers()
{
// Do some work and get a list of all user-objects.
List<User> userList = await _dbService.ReadAllUsersAsync();
return Ok(userList);
}
It would be nice if you could enlighten me with facts so I can either continue developing like I do right now or know that I have been doing it wrong due to misunderstanding the concept.
Please read the "Synchronous vs. Asynchronous Request Handling" section of Intro to Async/Await on ASP.NET.
Both can take multiple requests at once.
Yes. This is because ASP.NET is multithreaded. So, in the synchronous case, you just have multiple threads invoking the same action method (on different controller instances).
For non-multithreaded platforms (e.g., Node.js), you have to make the code asynchronous to handle multiple requests in the same process. But on ASP.NET it's optional.
Awaiting like this makes the code sequential again instead of having the benefits of Multitasking/Multithreading.
Yes, it is sequential, but it's not synchronous. It's sequential in the sense that the async method executes one statement at a time, and that request isn't complete until the async method completes. But it's not synchronous - the synchronous code is also sequential, but it blocks a thread until the method completes.
So why should I choose this signature instead of the one above?
If your backend can scale, then the benefit of asynchronous action methods is scalability. Specifically, asynchronous action methods yield their thread while the asynchronous operation is in progress - in this case, GetUsers is not taking up a thread while the database is performing its query.
The benefit can be hard to see in a testing environment, because your server has threads to spare, so there's no observable difference between calling an asynchronous method 10 times (taking up 0 threads) and calling a synchronous method 10 times (taking up 10 threads, with another 54 to spare). You can artificially restrict the number of threads in your ASP.NET server and then do some tests to see the difference.
In a real-world server, you usually want to make it as asynchronous as possible so that your threads are available for handling other requests. Or, as described here:
Bear in mind that asynchronous code does not replace the thread pool. This isn’t thread pool or asynchronous code; it’s thread pool and asynchronous code. Asynchronous code allows your application to make optimum use of the thread pool. It takes the existing thread pool and turns it up to 11.
Bear in mind the "if" above; this particularly applies to existing code. If you have just a single SQL server backend, and if pretty much all your actions query the db, then changing them to be asynchronous may not be useful, since the scalability bottleneck is usually the db server and not the web server. But if your web app could use threads to handle non-db requests, or if your db backend is scalable (NoSQL, SQL Azure, etc), then changing action methods to be asynchronous would likely help.
For new code, I recommend asynchronous methods by default. Asynchronous makes better use of server resources and is more cloud-friendly (i.e., less expensive for pay-as-you-go hosting).
If your DB Service class has an async method for getting the user then you should see benefits. As soon as the request goes out to the DB then it is waiting on a network or disk response back from the service at the other end. While it is doing this the thread can be freed up to do other work, such as servicing other requests. As it stands in the non-async version the thread will just block and wait for a response.
With async controller actions you can also get a CancellationToken which will allow you to quit early if the token is signalled because the client at the other end has terminated the connection (but that may not work with all web servers).
[HttpGet]
public async Task<IActionResult> GetUsers(CancellationToken ct)
{
ct.ThrowIfCancellationRequested();
// Do some work and get a list of all user-objects.
List<User> userList = await _dbService.ReadAllUsersAsync(ct);
return Ok(userList);
}
So, if you have an expensive set of operations and the client disconnects, you can stop processing the request because the client won't ever receive it. This frees up the application's time and resources to deal with requests where the client is interested in a result coming back.
However, if you have a very simple action that requires no async calls then I probably wouldn't worry about it, and leave it as it is.
You are missing something fundamental here.
When you use async Task<> you are effectively saying, "run all the I/O code asynchronously and free up processing threads to... process".
At scale, your app will be able to serve more requests/second because your I/O is not tying up your CPU intensive work and vice versa.
You're not seeing much benefit now, because you're probably testing locally with plenty of resources at hand.
See
Understanding CPU and I/O bound for asynchronous operations
Async in depth
As you know, ASP.NET is based on a multi-threaded model of request execution. To put it simply, each request is run in its own thread, contrary to other single thread execution approaches like the event-loop in nodejs.
Now, threads are a finite resource. If you exhaust your thread pool (available threads) you can't continue handling tasks efficiently (or in most cases at all). If you use synchronous execution for your action handlers, you occupy those threads from the pool (even if they don't need to be). It is important to understand that those threads handle requests, they don't do input/output. I/O is handled by separate processes which are independent of the ASP.NET request threads. So, if in your action you have a DB fetch operation that takes let's say 15 seconds to execute, you're forcing your current thread to wait idle 15 seconds for the DB result to be returned so it can continue executing code. Therefore, if you have 50 such requests, you'll have 50 threads occupied in basically sleep mode. Obviously, this is not very scalable and becomes a problem soon enough. In order to use your resources efficiently, it is a good idea to preserve the state of the executing request when an I/O operation is reached and free the thread to handle another request in the meantime. When the I/O operation completes, the state is reassembled and given to a free thread in the pool to resume the handling. That's why you use async handling. It lets you use your finite resources more efficiently and prevents such thread starvation. Of course, it is not an ultimate solution. It helps you scale your application for higher load. If you don't have the need for it, don't use it as it just adds overhead.
The result returns a task from an asynchronous (non-blocking) operation which represents some work that should be done. The task can tell you if the work is completed and if the operation returns a result, the task gives you the result which won't be available until the task is completed. You can learn more about C# asynchronous programming from the official Microsoft Docs:
https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task?view=net-5.0
Async operations return a Task(it is not the result, but a promise made that will have the results once the task is completed.
The async methods should be awaited so that it waits till the task is completed. if you await an async method, the return values won't be a task anymore and will be the results you expected.
Imagine this async method:
async Task<SomeResult> SomeMethod()
{
...
}
the following code:
var result = SomeMethod(); // the result is a Task<SomeResult> which may have not completed yet
var result = await SomeMethod(); // the result is type of SomeResult
Now, why do we use async methods instead of sync methods:
Imagine that a Method is doing some job that may take a long time to complete, when it is done sync all other requests will be waiting till the execution of this long taking job to complete, as they are all happening in the same thread. However when it is async, the task will be done in a (possibly another) thread and will not block the other requests.

Type of threading to use in c# for heavy IO operations

I am tasked with updating a c# application (non-gui) that is very single-threaded in it's operation and add multi-threading to it to get it to turn queues of work over quicker.
Each thread will need to perform a very minimal amount of calculations, but most of the work will be calling on and wait on SQL Server requests. So, lots of waiting as compared to CPU time.
A couple of requirements will be:
Running on some limited hardware (that is, just a couple of cores). The current system, when it's being "pushed" only takes about 25% CPU. But, since it's mostly doing waits for the SQL Server to respond (different server), we would like to the capability to have more threads than cores.
Be able to limit the number of threads. I also can't just have an unlimited number of threads going either. I don't mind doing the limiting myself via an Array, List, etc.
Be able to keep track of when these threads complete so that I can do some post-processing.
It just seems to me that the .NET Framework has so many different ways of doing threads, I'm not sure if one is better than the other for this task. I'm not sure if I should be using Task, Thread, ThreadPool, something else... It appers to me that async \ await model would not be a good fit in this case though as it waits on one specific task to complete.
I'm not sure if I should be using Task, Thread, ThreadPool, something else...
In your case it matters less than you would think. You can focus on what fits your (existing) code style and dataflow the best.
since it's mostly doing waits for the SQL Server to respond
Your main goal would be to get as many of those SQL queries going in parallel as possible.
Be able to limit the number of threads.
Don't worry about that too much. On 4 cores, with 25% CPU, you can easily have 100 threads going. More on 64bit. But you don't want 1000s of threads. A .net Thread uses 1MB minimum, estimate how much RAM you can spare.
So it depends on your application, how many queries can you get running at the same time. Worry about thread-safety first.
When the number of parallel queries is > 1000, you will need async/await to run on fewer threads.
As long as it is < 100, just let threads block on I/O. Parallel.ForEach() , Parallel.Invoke() etc look like good tools.
The 100 - 1000 range is the grey area.
add multi-threading to it to get it to turn queues of work over quicker.
Each thread will need to perform a very minimal amount of calculations, but most of the work will be calling on and wait on SQL Server requests. So, lots of waiting as compared to CPU time.
With that kind of processing, it's not clear how multithreading will benefit you. Multithreading is one form of concurrency, and since your workload is primarily I/O-bound, asynchrony (and not multithreading) would be the first thing to consider.
It just seems to me that the .NET Framework has so many different ways of doing threads, I'm not sure if one is better than the other for this task.
Indeed. For reference, Thread and ThreadPool are pretty much legacy these days; there are much better higher-level APIs. Task should also be rare if used as a delegate task (e.g., Task.Factory.StartNew).
It appers to me that async \ await model would not be a good fit in this case though as it waits on one specific task to complete.
await will wait on one task at a time, yes. Task.WhenAll can be used to combine
multiple tasks and then you can await on the combined task.
get it to turn queues of work over quicker.
Be able to limit the number of threads.
Be able to keep track of when these threads complete so that I can do some post-processing.
It sounds to me that TPL Dataflow would be the best approach for your system. Dataflow allows you to define a "pipeline" through which data flows, with some steps being asynchronous (e.g., querying SQL Server) and other steps being parallel (e.g., data processing).
I was asking a high-level question to try and get back a high-level answer.
You may be interested in my book.
The TPL Dataflow library is probably one of the best options for this job. Here is how you could construct a simple dataflow pipeline consisting of two blocks. The first block accepts a filepath and produces some intermediate data, that can be later inserted to the database. The second block consumes the data coming from the first block, by sending them to the database.
var inputBlock = new TransformBlock<string, IntermediateData>(filePath =>
{
return GetIntermediateDataFromFilePath(filePath);
}, new ExecutionDataflowBlockOptions()
{
MaxDegreeOfParallelism = Environment.ProcessorCount // What the local machine can handle
});
var databaseBlock = new ActionBlock<IntermediateData>(item =>
{
SaveItemToDatabase(item);
}, new ExecutionDataflowBlockOptions()
{
MaxDegreeOfParallelism = 20 // What the database server can handle
});
inputBlock.LinkTo(databaseBlock);
Now every time a user uploads a file, you just save the file in a temp path, and post the path to the first block:
inputBlock.Post(filePath);
And that's it. The data will flow from the first to the last block of the pipeline automatically, transformed and processed along the way, according to the configuration of each block.
This is an intentionally simplified example to demonstrate the basic functionality. A production-ready implementation will probably have more options defined, like the CancellationToken and BoundedCapacity, will watch the return value of inputBlock.Post to react in case the block can't accept the job, may have completion propagation, watch the databaseBlock.Completion property for errors etc.
If you are interested at following this route, it would be a good idea to study the library a bit, in order to become familiar with the options available. For example there is a TransformManyBlock available, suitable for producing multiple outputs from a single input. The BatchBlock may also be useful in some cases.
The TPL Dataflow is built-in the .NET Core, and available as a package for .NET Framework. It has some learning curve, and some gotchas to be aware of, but it's nothing terrible.
It appers to me that async \ await model would not be a good fit in this case though as it waits on one specific task to complete.
That is wrong. Async/await is just a syntax to simplify a state-machine mechanism for asynchronous code. It waits without consuming any thread. in other words async keyword does not create thread and await does not hold up any thread.
Be able to limit the number of threads
see How to limit the amount of concurrent async I/O operations?
Be able to keep track of when these threads complete so that I can do some post-processing.
If you don't use "fire and forget" pattern then you can keep track of the task and its exceptions just by writing await task
var task = MethodAsync();
await task;
PostProcessing();
async Task MethodAsync(){ ... }
Or for a similar approach you can use ContinueWith:
var task = MethodAsync();
await task.ContinueWith(() => PostProcessing());
async Task MethodAsync(){ ... }
read more:
Releasing threads during async tasks
https://learn.microsoft.com/en-us/dotnet/standard/asynchronous-programming-patterns/?redirectedfrom=MSDN

C# .NET choice of Multithreading approach

I've looked over multiple similar questions on SO, but I still couldn't answer my own question.
I have a console app (an Azure Webjob actually) which does file processing and DB management. Some heavy data being downloaded from multiple sources and processed on the DB.
Here's an example of my code:
var dbLongIndpendentProcess = doProcesAsync();
var myfilesTasks = files.Select(file => Task.Run(
async () =>
{
// files processing
}
await myfilesTasks.WhenAll();
await dbLongIndpendentProcess;
// continue with other stuff;
It all works fine and does what I am expecting it to do. There are other tasks running in this whole process, but I guess the idea is clear from the code above.
My question: Is this a fair way of approaching this, or would I get more performance (or sense?) by doing the good old "manual" multithreading? The main reason I chose this approach was that it's simple and straightforward.
However, wasn't async/await primarily aimed at doing asynchronous not to block the main (UI) thread. Here I don't have any UI and I am not doing anything. event-driven.
Thanks,
I don't think you're multithreading by using this approach (except the single Task.Run), async doesn't generally run things on separate threads, it only prevents things from blocking. See: https://msdn.microsoft.com/en-gb/library/mt674882.aspx#Anchor_5
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.
It would be much better to use tasks for the things you want to multithread, then you can take better advantage of machine cores and resources. You might want to look at a task based solution such as Pipelining (which may work in this scenario) etc...: https://msdn.microsoft.com/en-gb/library/ff963548.aspx or another alternative.

Why does an async single task run faster than a normal single task?

I have a method which has just one task to do and has to wait for that task to complete:
public async Task<JsonResult> GetAllAsync()
{
var result = await this.GetAllDBAsync();
return Json(result, JsonRequestBehavior.AllowGet);
}
public async Task<List<TblSubjectSubset>> GetAllDBAsync()
{
return await model.TblSubjectSubsets.ToListAsync();
}
It is significantly faster than when I run it without async-await.
We know
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
According to this link: https://msdn.microsoft.com/en-us/library/hh191443.aspx#BKMK_Threads. What is the reason for being faster when we don't have another thread to handle the job?
"Asynchronous" does not mean "faster."
"Asynchronous" means "performs its operation in a way that it does not require a thread for the duration of the operation, thus allowing that thread to be used for other work."
In this case, you're testing a single request. The asynchronous request will "yield" its thread to the ASP.NET thread pool... which has no other use for it, since there are no other requests.
I fully expect asynchronous handlers to run slower than synchronous handlers. This is for a variety of reasons: there's the overhead of the async/await state machine, and extra work when the task completes to have its thread enter the request context. Besides this, the Win32 API layer is still heavily optimized for synchronous calls (expect this to change gradually over the next decade or so).
So, why use asynchronous handlers then?
For scalability reasons.
Consider an ASP.NET server that is serving more than one request - hundreds or thousands of requests instead of a single one. In that case, ASP.NET will be very grateful for the thread returned to it during its request processing. It can immediately use that thread to handle other requests. Asynchronous requests allow ASP.NET to handle more requests with fewer threads.
This is assuming your backend can scale, of course. If every request has to hit a single SQL Server, then your scalability bottleneck will probably be your database, not your web server.
But if your situation calls for it, asynchronous code can be a great boost to your web server scalability.
For more information, see my article on async ASP.NET.
I agree with Orbittman when he mentions the overhead involved in the application architecture. It doesn't make for a very good benchmark premise since you can't be sure if the degradation can indeed be solely attributed to the async vs non-async calls.
I've created a really simple benchmark to get a rough comparison between an async and a synchronous call and async loses every time in the overall timing actually, though the data gathering section always seems to end up the same. Have a look: https://gist.github.com/mattGuima/25cb7893616d6baaf970
Having said that, the same thought regarding the architecture applies. Frameworks handle async calls differently: Async and await - difference between console, Windows Forms and ASP.NET
The main thing to remember is to never confuse async with performance gain, because it is completely unrelated and most often it will result on no gain at all, specially with CPU-bound code. Look at the Parallel library for that instead.
Async await is not the silver bullet that some people think it is and in your example is not required. If you were processing the result of the awaitable operation after you received it then you would be able to return a task and continue on the calling thread. You wouldn't have to then wait for the rest of the operation to complete. You would be correct to remove the async/await in the above code.
It's not really possible to answer the question without seeing the calling code either as it depends on what the context is trying to trying to do with the response. What you are getting back is not just a Task but a task in the context of the method that will continue when complete. See http://codeblog.jonskeet.uk/category/eduasync/ for much better information regarding the inner workings of async/await.
Lastly I would question your timings as with an Ajax request to a database and back there other areas with potentially greater latency, such as the HTTP request and response and the DB connection itself. I assume that you're using an ORM and that alone can cause an overhead. I wonder whether it's the async/await that is the problem.

Categories

Resources