Probably one big dumb question for many, but ajax is already async, so is there any point in making for example, a method that returns me some data from database async?
using async, two or more operations are running in different contexts (thread) so that they can run concurrently and do not block each other. :)
Related
How big of an effect do actions have on performance, more precisely: dispatching said actions?
Let's say the same action is dispatched 10 times in a row on a single user interaction with the UI, how would that affect performance? Or, does it even affect performance?
It primarily depends if React batches the following render. You can either have one render or one dispatch per render - that's totally up to React. Normally React batches in event handlers and effects, but not in async code. You can manually control this by using the batch api (re-exported with that name in react-redux).
Generally though, the recommendation is to dispatch one action that described what happened and all the necessary information and let any number of reducers react to that. Keep your logic out of your application layer (=React) and inside of your business layer (=Redux).
https://redux.js.org/style-guide/style-guide/#model-actions-as-events-not-setters
https://redux.js.org/style-guide/style-guide/#allow-many-reducers-to-respond-to-the-same-action
https://redux.js.org/style-guide/style-guide/#avoid-dispatching-many-actions-sequentially
I have an Asp.net MVC 5 application that has:
Web UI layer
Business Logic layer
Data repositories layer
They are also referenced in this order. UI only accesses business logic, and business logic references repositories.
As with 99% of applications everything can and should be executed synchronously except calls into database (or other I/O expensive operations). That's why I would like to make Data layer asynchronous but without affecting upper layers to make all upper calling methods async (all the way to controller actions).
Is that possible?
What I was thinking to do
I was thinking of changing things this way.
Data layer method
public async Task<SomeEntity> GetData()
{
return await Task.Run<SomeEntity>(() => ...);
}
Business logic method
public SomeEntity GetData()
{
return this.repo.GetData().Result;
}
Questions
Does this make sense and would I actually get my code to execute in asynchronous manner?
Update
After reading Stephen Cleary's blog post it made it more clear to me that whole call stack to the bottom (data layer that splits the synchronisity) is being split by the data async call hence all calls on the stack should be async and split as well.
If this thinking is correct then are my assumptions correct when I say that
In order to not have the whole synchronous call stack converted to async we should create a separate thread that would work asynchronously and our synchronous thread would use it.
Question 2
Is this assumption correct and if it is, is that the only way to keep some parts synchronous?
As with 99% of applications everything can and should be executed synchronously except calls into database.
Not at all. Anything that is I/O-based should be asynchronous.
So, the data layer does database I/O, and should be asynchronous.
The business logic layer uses the data layer, which is I/O-based, and should be asynchronous.
The UI layer uses the business logic layer, which is I/O-based, and should be asynchronous.
Of course, only those methods that are actually I/O-based should be made asynchronous; the rest should be synchronous. But I find that in data-access-heavy applications, they should be almost entirely asynchronous.
Does this make sense and would I actually get my code to execute in asynchronous manner?
No. Sorry, but you should never wrap asynchronous code in Task.Run and block on it in an ASP.NET application. All that does is use up more threads than necessary for processing your request. It would be better to keep it all synchronous than to use multiple threads to keep it synchronous.
On ASP.NET, you have to allow the asynchrony to propagate through all layers in order to have asynchronous actions/handlers (and all the benefits that come with it, namely, scalability).
Mixing sync with async in this manor can be dangerous as it invites deadlocks. Stephen Cleary explains this very well here:
http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html
(This probably duplicates the question ASP.NET MVC4 Async controller - Why to use?, but about webapi, and I do not agree with answers in there)
Suppose I have a long running SQL request. Its data should be than serialized to JSON and sent to browser (as a response for xhr request). Sample code:
public class DataController : ApiController
{
public Task<Data> Get()
{
return LoadDataAsync(); // Load data asynchronously?
}
}
What actually happens when I do $.getJson('api/data', ...) (see this poster http://www.asp.net/posters/web-api/ASP.NET-Web-API-Poster.pdf):
[IIS] Request is accepted by IIS.
[IIS] IIS waits for one thread [THREAD] from the managed pool (http://msdn.microsoft.com/en-us/library/0ka9477y(v=vs.110).aspx) and starts work in it.
[THREAD] Webapi Creates new DataController object in that thread, and other classes.
[THREAD] Uses task-parallel lib to start a sql-query in [THREAD2]
[THREAD] goes back to managed pool, ready for other processing
[THREAD2] works with sql driver, reads data as it ready and invokes [THREAD3] to reply for xhr request
[THREAD3] sends response.
Please, feel free to correct me, if there's something wrong.
In the question above, they say, the point and profit is, that [THREAD2] is not from The Managed Pool, however MSDN article (link above) says that
By default, parallel library types like Task and Task<TResult> use thread pool threads to run tasks.
So I make a conclusion, that all THREE THREADS are from managed pool.
Furthermore, if I used synchronous method, I would still keep my server responsive, using only one thread (from the precious thread pool).
So, what's the actual point of swapping from 1 thread to 3 threads? Why not just maximize threads in thread pool?
Are there any clearly useful ways of using async controllers?
I think the key misunderstanding is around how async tasks work. I have an async intro on my blog that may help.
In particular, a Task returned by an async method does not run any code. Rather, it is just a convenient way to notify callers of the result of that method. The MSDN docs you quoted only apply to tasks that actually run code, e.g., Task.Run.
BTW, the poster you referenced has nothing to do with threads. Here's what happens in an async database request (slightly simplified):
Request is accepted by IIS and passed to ASP.NET.
ASP.NET takes one of its thread pool threads and assigns it to that request.
WebApi creates DataController etc.
The controller action starts an asynchronous SQL query.
The request thread returns to the thread pool. There are now no threads processing the request.
When the result arrives from the SQL server, a thread pool thread reads the response.
That thread pool thread notifies the request that it is ready to continue processing.
Since ASP.NET knows that no other threads are handling that request, it just assigns that same thread the request so it can finish it off directly.
If you want some proof-of-concept code, I have an old Gist that artificially restricts the ASP.NET thread pool to the number of cores (which is its minimum setting) and then does N+1 synchronous and asynchronous requests. That code just does a delay for a second instead of contacting a SQL server, but the general principle is the same.
The profit of asynchronous actions is that while the controller is waiting for the sql query to finish no threads are allocated for this request, while if you used a synchronous method a thread would be locked up in the execution of this method from the start to end of that method. While SQL server is doing its job the thread isn't doing anything but waiting.
If you use asynchronous methods this same thread can respond to other requests while SQL server is doing its thing.
I believe your steps are wrong at step 4, I don't think it will create a new thread to do the SQL query. At 6 there isn't created a new thread, it is just one of the available threads that will be used to continue from where the first thread left off. The thread at 6 could be the same as started the async operation.
The point of async is not to make an application multi threaded but rather to let a single threaded application carry on with something different instead of waiting for a response from an external call that is executing on a different thread or process.
Consider a desk top application that shows stock prices from different exchanges. The application needs to make a couple of REST / http calls to get some data from each of the remote stock exchange servers.
A single threaded application would make the first call, wait doing nothing until it got the first set of prices, update it's window, then make a call to the next external stock price server, again wait doing nothing until it got the prices, update it's window... etc..
We could go all multi threaded kick off the requests in parallel and update the screen in parallel, but since most of the time is spent waiting for a response from the remote server this seems overkill.
It might be better for the thread to:
Make a request for the first server but instead of waiting for the answer leave a marker, a place to come back to when the prices arrive and move on to issuing the second request, again leaving a marker of a place to come back to...etc.
When all the requests have been issued the application execution thread can go on to dealing with user input or what ever is required.
Now when a response from one of the servers is received the thread can be directed to continue from the marker it laid down previously and update the window.
All of the above could have been coded long hand, single threaded, but was so horrendous going multi threaded was often easier. Now the process of leaving the marker and coming back is done by the compiler when we write async/await. All single threaded.
There are two key points here:
1) Multi threaded does still happen! The processing of our request for stock prices happens on a different thread (on a different machine). If we were doing db access the same would be true. In examples where the wait is for a timer, the timer runs on a different thread. Our application though is single threaded, the execution point just jumps around (in a controlled manner) while external threads execute
2) We lose the benefit of async execution as soon as the application requires an async operation to complete. Consider an application showing the price of coffee from two exchanges, the application could initiate the requests and update it's windows asynchronously on a single thread, but now if the application also calculated the difference in price between two exchanges it would have to wait for the async calls to complete. This is forced on us because an async method (such as one we might write to call an exchange for a stock price) does not return the stock price but a Task, which can be thought of as a way to get back to the marker that was laid down so the function can complete and return the stock price.
This means that every function that calls an async function needs to be async or to wait for the "other thread/process/machine" call at the bottom of the call stack to complete, and if we are waiting for the bottom call to complete well why bother with async at all?
When writing a web api, IIS or other host is the desktop application, we write our controller methods async so that the host can execute other methods on our thread to service other requests while our code is waiting for a response from work on a different thread/process/machine.
I my opinion the following describes a clear advantage of async controllers over synchronous ones.
A web application using synchronous methods to service high latency
calls where the thread pool grows to the .NET 4.5 default maximum of
5, 000 threads would consume approximately 5 GB more memory than an
application able the service the same requests using asynchronous
methods and only 50 threads. When you’re doing asynchronous work,
you’re not always using a thread. For example, when you make an
asynchronous web service request, ASP.NET will not be using any
threads between the async method call and the await. Using the thread
pool to service requests with high latency can lead to a large memory
footprint and poor utilization of the server hardware.
from Using Asynchronous Methods in ASP.NET MVC 4
I'm trying to mix AsyncController with dependency injection. The MVC app in question gets nearly all of its data through async web service calls. We are wrapping the async work in Tasks from the TPL, and notifying the controller's AsyncManager when these tasks complete.
Sometimes we have to touch the HttpContext in continuations of these tasks - adding a cookie, whatever. The correct way to do this according to Using an Asynchronous Controller in ASP.NET MVC is to call the AsyncManager.Sync method. This will propagate the ASP.NET thread context, including the HttpContext, to the current thread, execute the callback, then restore the previous context.
However, that article also says:
Calling Sync() from a thread that is already under the control of ASP.NET has undefined behavior.
This isn't a problem if you do all of your work in the controller, since you generally know what thread you should be on in the continuations. But what I'm trying to do is create a middle layer in between our async data access and our async controllers. So these are also async. Everything is wired up by a DI container.
So like before, some of the components in a call chain will need to work with the "current" HttpContext. For example, after logon we want to store the "session" token we get back from a single-sign-on service. The abstraction for the thing that does that is ISessionStore. Think of a CookieSessionStore that puts a cookie on the response, or grabs the cookie from the request.
Two problems I can see with this:
The components do not have access to AsyncManager or even know they're being used within a controller.
The components do not know which thread they are being invoked from, and so AsyncManager.Sync or any equivalent is theoretically problematic anyway.
To solve #1, I am basically injecting an object that grabs TaskScheduler.FromCurrentSynchronizationContext() at the beginning of the request, and can invoke an action via a Task started with that scheduler, taking the HttpContextBase as an argument.
That is, from my components, I can call something similar to:
MySyncObject.Sync(httpContext => /* Add a cookie or something else */);
I have not yet observed any problems with this, but I am concerned about problem #2. I have looked at both AsyncManager and SynchronizationContextTaskScheduler in Reflector, and they operate similarly, executing the callback on the ASP.NET SynchronizationContext. And that scares me :)
I had a bit of hope when I saw that the task scheduler implementation will invoke the directly rather than going through the synchronization context if it's inlining. But unfortunately, this doesn't seem to happen through the normal Task.Start(scheduler) code-path. Rather, tasks can be inlined in other circumstances, like if they are being waited upon before they start.
So my questions are:
Am I going to run into trouble here with this approach?
Is there a better way?
Is the usefulness of synchronizing in this scenario merely to serialize access to the non-thread-safe HttpContext? i.e. could I get away with a thread-safe HttpContextBase wrapper instead (ick)?
Relying on thread-local statics is rarely a good idea. While HttpContext.Current relies on that mechanism and it has worked for years, now that we're going async, that approach is quickly deteriorating. It's much better to capture the value of this static as a local variable and pass that around with your async work so you always have it. So, for example:
public async Task<ActionResult> MyAction() {
var context = HttpContext.Current;
await Task.Yield();
var item = context.Items["something"];
await Task.Yield();
return new EmptyResult();
}
Or even better, avoid HttpContext.Current altogether if you're in MVC:
public async Task<ActionResult> MyAction() {
await Task.Yield();
var item = this.HttpContext.Items["something"];
await Task.Yield();
return new EmptyResult();
}
Arguably, your middleware business logic especially shouldn't be relying on HttpContext or anything else in the ASP.NET libraries. So assuming your middleware calls back out to your controller (via callbacks, interfaces, etc.) to set cookies, you'll then have this.HttpContext available to use for accessing that context.
Background:
http://www.hanselman.com/blog/HanselminutesPodcast188ASPNETMVC2BetaWithPhilHaack.aspx
Start from 27:15,RenderAction has been discussed at 28:43 that a RenderAction will not be part of Asynchronocity as an asyncronous action method called.
(Let's say your home portal index action calling 1.GetNews 2.GetWeather 3.GetStock asynchronously.You have have a RenderAction displaying user recent posts on the same view. (GetUserRecentPosts))
Questions
What if RenderActions themselves are asynchronous ?
Would GetUserRecentPosts be called only after home index completed its action even though?
Should RenderActions be rendered asynchronously on a view by default?
I don't think you can do this successfully. The point where you could benefit from asynch processing has already passed when your views start rendering. The MVC pipeline that sets up the begin/end methods has already completed and the View has no way to get back into it on the same request. Seems like you may be stuck with synchronous processing OR devise some way to retrieve all your data up front and cache it in TempData or something for rendering.
Lift framework in Scala is probably the only one that I am aware of that has parallel partial actions which will not block the rendering of the main content but will use Comet-push to deliver partial view content for those blocks which may take a while to get data for.
to use it, just wrap a block in your view inside a parallel node
<lift:parallel>
//this is where Html.RenderAction("GottaFetchNetworkDataFromSomewhereView");
//this is where Html.RenderAction("GottaFetchNetworkDataFromSomewhereView2");
// would go
</lift:parallel>
Lift will also take care of connection starvation of your page to manage http requests in the appropriate manner so that browser pushes are not "waiting 'round".
Unfortunately, ASP.NET MVC has poor Comet support. There's not much outside of Asynchronous Controllers, which is an improvement but not as elegant as, say, Akka's framework suspend() method for long-polling.