I'm using async/await in WebApi Controllers according to this article: https://msdn.microsoft.com/en-us/magazine/dn802603.aspx
Hava look at this simplified code in my controller:
DataBaseData = await Task.Run( () => GetDataFunction() );
GetDataFunction is a function that will open a database connection, open a reader and read the data from the database.
In many examples I see it handled differently. The GetDataFunction itself is awaited. And within the function every single step is awaited. For example:
- connection.OpenAsync
- reader.ReadAsycnc
- reader.IsDBNullAsync
Why is this good practice? Why not just start a thread for the whole database access (with Task.Run)?
Update: Thanks for the help. Now I got it. I did not get, that the asynchronous Api's do not start threads themselves. This really helped: blog.stephencleary.com/2013/11/there-is-no-thread.html
It's all about resource management and sharing.
When using
connection.Open()
method the thread that calls it has to wait for the connection to actually open. While waiting it does nothing but consume the CPU slice allocated to it by the operating system. However, when youawait connection.OpenAsync()
the thread frees up its resources and the OS can redistribute them to other threads.Now, there's a catch: to actually gain from asynchronous calls they should take longer than the time it takes for the OS to switch contexts otherwise it will incur a drop in application performance.
The practice of awaiting on
connection.OpenAsync()
,reader.ReadAsync()
etc. is due to the fact that these are potentially long running operations. In a system where de database resides on another machine and it is under a heavy load of requests, connecting to the database and getting the results of a query will take some time. Instead of blocking the CPU while waiting on the results to arrive why not allocate that time slice to another worker thread that waits in the scheduler queue to render the response for another client?Now, about starting another thread for data access: don't do that!. Each new thread gets allocated about 1MB of memory space so beside wasting CPU time while waiting for database operations to finish you'll be wasting memory also. Furthermore, having such a heavy memory footprint would require a lot more runs for Garbage Collector which will freeze all of your threads when running.
Using
Task.Run()
will schedule the data access operations on a thread from theThreadPool
but you will lose the benefit of sharing the CPU time with another thread while waiting for database server to respond.The article you linked to states:
In other words, avoid
Task.Run
on ASP.NET.It's because the asynchronous APIs do not use other threads. The entire point of
async
/await
is to free up the current thread; not use another thread. I have a blog post describing howasync
works without needing threads.So, the
Task.Run
(or custom thread) approach will use up (block) a thread while getting data from the database. Proper asynchronous methods (e.g., EF6 or the ADO.NET asynchronous APIs) do not; they allow the request thread to be used for other requests while that request is waiting for the database response.I assume you are wondering why using
instead of
As you can see in Task.Run(Func) under the section Remarks there is written:
That means, you should use
await GetDataFunction
.