async/await in background in ASP.NET WebApi - asp.net

Let's suppose i have the following async method that needs fairly long time until completing its work:
void async Task LongWork()
{
await LONGWORK() // ... long work
}
Now, in an web api, i would like to run that work in a background (i.e., i want to return the Http Request after starting that LongWork() but before its completion:
I can think of three approaches to achieve this:
1) public async Task<string> WebApi()
{
... // do another work
await Task.Factory.StartNew(() => LongWork());
return "ok";
}
2) public async Task<string> WebApi()
{
... // do another work
await Task.Factory.StartNew(async () => await LongWork());
return "ok";
}
3) public async Task<string> WebApi()
{
... // do another work
Task.Factory.StartNew(async () => await LongWork());
return "ok";
}
Q1: What's the difference between approach #1 and #2?
Q2: What is the right way to, in the ASP.NET world, run a method (in this example, LongWork() containing some async/await pairs in a background thread?
In particular, in #3, there's no "await" before Task.Factory.StartNew(async () => await LongWork()). Is it fine?
Thanks!

Q1: What's the difference between approach #1 and #2?
#1 has less overhead. That is the only difference.
Q2: What is the right way to, in the ASP.NET world, run a method (in this example, LongWork() containing some async/await pairs in a background thread?
None of the options you provided. For one thing, they all use Task.Factory.StartNew without specifying a TaskScheduler, which is dangerous (as I describe on my blog). They should use Task.Run instead. However, even if you use Task.Run, you will run into a more serious underlying problem.
The underlying problem is this: the HTTP protocol is centered around each request having exactly one matching response. When an HTTP server (such as ASP.NET) knows that there are no outstanding requests, it will make assumptions like "it's safe to recycle the worker process".
I describe this problem in more detail on my blog. Also in that blog post is a type BackgroundTaskManager that registers background tasks with the ASP.NET runtime and (correctly) executes them via Task.Run. You should only use BackgroundTaskManager if you read the blog post and understand and accept that this is still dangerous and unsafe.
A far better (read: more reliable) solution is to first write out a representation of the work to be done to persistent storage (e.g., an Azure queue) and have an independent backend process (e.g., an Azure worker role) that processes requests from the queue.

Related

How to create and start Task, and have a completion handler, which runs on completion?

...without async await...
I would like to demonstrate the classic completion handler logic with Task library. (not with the pure Thread object) So I would like to create a Task instance, run it (against the default thread pool, or any way), and have a completion handler, which runs (probably on the Task's thread) on completion and access to the result.
(I do know now we can use async await, also know about marshaling, also know about ASP.NET threads and contexts, please do not explain those.)
I would like to demonstrate the classic completion handler logic with Task library.
I really don't think this is very useful. It sounds like you're describing continuation passing style, which was not widely adopted among .NET libraries. There was one HTTP library using it, but other than that I did not see much adoption of that pattern in .NET at all. On the other hand, JavaScript (particularly server-side JS) did use CPS quite a bit.
That said, if you really want to do it, you can:
public static void Run<T>(Func<T> action, Action<Exception> onError, Action<T> onComplete)
{
Task.Run(action).ContinueWith(
t =>
{
T result;
try
{
result = t.Result;
}
catch (Exception ex)
{
onError(ex);
return;
}
onComplete(result);
},
default,
TaskContinuationOptions.ExecuteSynchronously,
TaskScheduler.Default);
}

How to call a async method from synchronous method?

I'm trying to call an asynchronous method from a synchronous method like below:
1. public List<Words> Get(string code)
{
Task<List<Words>> taskWords = GetWordsAsync(code);
var result = taskWords.Result;
return result;
}
private async Task<List<Words>> GetWordsAsync(string code)
{
var result = await codeService.GetWordsByCodeAsync(code);
return result;
}
But this lead to a deadlock, await is not getting the results from the method - GetWordsByCodeAsync
I've done a bit of research and came to know that if we are calling an async method from synchronous method we should use Task.Run
When I changed the code like below, it worked:
2. public List<Words> Get(string code)
{
Task<List<Words>> taskWords = Task.Run<List<Words>>(async () => await GetWordsAsync(code);
var result = taskWords.Result;
return result;
}
private async Task<List<Words>> GetWordsAsync(string code)
{
var result = await codeService.GetWordsByCodeAsync(code);
return result;
}
But I didn't get the context, why it caused a deadlock for 1st way and 2nd one worked fine.
I'd like to know:
What's the difference between two ways?
Is second one the correct way to call async method from synchronous method?
Will using the second method also causes a deadlock at some point of time if the result is large? or is it fail proof(safe) method to use?
Also, please suggest any best practices to better do it as I have to do 5 async calls from a synchronous method - just like taskWords, I have taskSentences etc.,
Note: I don't want to change everything to async. I want to call async method from synchronous method.
I don't want to change everything to async. I want to call async method from synchronous method.
From a technical standpoint, this doesn't make sense. Asynchronous means it doesn't block the calling thread; synchronous means it does. So you understand that if you block on asynchronous code, then it's no longer truly asynchronous? The only benefit to asynchronous code is that it doesn't block the calling thread, so if you block on the asynchronous code, you're removing all the benefit of asynchrony in the first place.
The only good answer is to go async all the way. There are some rare scenarios where that's not possible, though.
What's the difference between two ways?
The first one executes the asynchronous code directly and then blocks the calling thread, waiting for it to finish. You're running into a deadlock because the asynchronous code is attempting to resume on the calling context (which await does by default), and presumably you're running this code on a UI thread or in an ASP.NET Classic request context, which only allow one thread in the context at a time. There's already a thread in the context (the one blocking, waiting for the task to finish), so the async method cannot resume and actually finish.
The second one executes the asynchronous code on a thread pool thread and then blocks the calling thread, waiting for it to finish. There is no deadlock here because the asynchronous code resumes on its calling context, which is a thread pool context, so it just continues executing on any available thread pool thread.
Is second one the correct way to call async method from synchronous method?
There is no "correct" way to do this. There are a variety of hacks, each of which has different drawbacks, and none of which work in every situation.
Will using the second method also causes a deadlock at some point of time if the result is large? or is it fail proof(safe) method to use?
It will not deadlock. What it does, though, is execute GetWordsAsync on a thread pool thread. As long as GetWordsAsync can be run on a thread pool thread, then it will work.
Also, please suggest any best practices to better do it
I have written an article on the subject. In your case, if GetWordsAsync is safe to call on a thread pool thread, then the "blocking thread pool hack" is acceptable.
Note that this is not the best solution; the best solution is to go async all the way. But the blocking thread pool hack is an acceptable hack if you must call asynchronous code from synchronous code (again, it's "acceptable" only if GetWordsAsync is safe to call on a thread pool thread).
I would recommend using GetAwaiter().GetResult() rather than Result, in order to avoid the AggregateException wrapper on error. Also, the explicit type arguments are unnecessary, and you can elide async/await in this case:
var taskWords = Task.Run(() => GetWordsAsync(code));
return taskWords.GetAwaiter().GetResult();

ASP.NET Core, overkilling Task.Run()?

Lets say we have an ASP.NET Core receiving a string as a payload, size order of couple of megabytes. First method implementation:
[HttpPost("updateinfos")]
public async Task UpdateInfos()
{
var len = (int)this.Request.ContentLength;
byte[] b = new byte[len];
await this.Request.Body.ReadAsync(b,0,len);
var content = Encoding.UTF8.GetString(b);
.....
}
Body is read with ReadAsync, this is good since we have I/O stuff on socket and having it asynchronous is for free due to the nature of the call itself. But if we have a look after, the GetString() method, is purely CPU, is blocking with linear complexity. Anyway this affect somehow the performance since other clients wait for my bytes to get converted in string. I think to avoid this the solution is to run GetString() on the thread pool, by this:
[HttpPost("updateinfos")]
public async Task UpdateInfos()
{
var len = (int)this.Request.ContentLength;
byte[] b = new byte[len];
await this.Request.Body.ReadAsync(b,0,len);
var content = await Task.Run(()=>ASCIIEncoding.UTF8.GetString(b));
.....
}
please don't mind the return right now, something more has to be done in the function.
So the question, is the second approach overkilling? If so, what is the boundary to discriminate what could be run as blocking and what has to be moved to another thread?
You are very much abusing Task.Run there. Task.Run is used to off-load work onto a different thread and asynchronously wait for it to complete. So every Task.Run call will cause thread context switches. Of course, that is usually a very bad idea to do for things that should not run on their own thread.
Things like ASCIIEncoding.UTF8.GetString(b) are really fast. The overhead involved in creating and managing a thread that encapsulates this is much larger than just executing this directly on the same thread.
You should generally use Task.Run only to off-load (primarily synchronous) work that can benefit from running on its own thread. Or in cases, where you have work that would take a bit longer but block the current execution.
In your example, that is simply not the case, so you should just call those methods synchronously.
If you really want to reduce the work for that code, you should look at how to work properly streams. What you do in your code is read the request body stream completely and only then you work on it (trying to translate into a string).
Instead of separating the process of reading the binary stream and then translating it into a string, you could just read the stream as a string directly using a StreamReader. That way, you can read the request body directly, even asynchronously. So depending on what you actually do with it afterwards, that may be a lot more efficient.

How to properly use Task object in .NET

I am working on an ASP .NET MVC 5 application that requires me to use the Task objects that were introduced in .NET 4.0. I am browsing through a few links that give an overview of Task objects. However, I could use a bit of help to check if I am going in the right direction.
Here is the stub that is generated by Visual Studio:
public Task<MyAppUser> FindByNameAsync(string userName) {
throw new System.NotImplementedException();
}
I have written a method called mySearch() that searches through a list. I could use this function for my implementation:
public Task<MyAppUser> FindByNameAsync(string userName) {
MyAppUser val = mySearch(userName);
return Task<MyAppUser>.FromResult<MyAppUser>(val);
}
While this may work, I am thinking I am not really utilizing the Task paradigm properly. Perhaps I can write the code as follows:
public Task<MyAppUser> FindByNameAsync(string userName) {
return Task<MyAppUser>.Factory.StartNew(() => mySearch(userName));
}
As I understand, I am simply returning a delegate as a Task object which the ASP.NET engine will execute as needed.
Am I using the Task paradigm correctly?
Don't ever return a new Task from an XXXAsync method - that's almost the worst thing you can do. In your case, using Task.FromResult is probably the best option (if you are indeed forced to use the XXXAsync methods and if you really don't have asynchronous I/O for the search method). In a web application, it's better to do the whole thing synchronously rather than appearing asynchronous while still taking up a different thread.
The reasoning is simple - asynchronous methods are a great way to conserve resources. Asynchronous I/O doesn't require a thread, so you can afford to reuse the current thread for other work until the data is actually ready. In ASP.NET, the callback will be posted back to a ThreadPool thread, so you've managed to increase your throughput essentially for free.
If you fake the asynchronous method by using Task.FromResult, it's true that this is lost. However, unlike in WinForms or WPF, you're not freezing the GUI, so there's no point in masking the lacking asynchronicity by spawning a new thread.
When you do the faking by using TaskFactory.StartNew or Task.Run, you're only making things worse, essentially - it's true that you release the original thread as with proper async I/O, but you also claim a new thread from the ThreadPool - so you're still blocking one thread, you just added a bunch of extra work for the plumbing.
#Luaan's answer is quite good. I just want to expound on a couple of principles for using async on ASP.NET.
1) Use synchronous method signatures for synchronous work.
I'm not sure why VS is generating an asynchronous stub. Since your mySearch just "searches through a list" (a synchronous operation), then your method should look like this instead:
public MyAppUser FindByName(string userName) {
return mySearch(userName);
}
2) Use async/await for asynchronous work (i.e., anything doing I/O). Do not use Task.Run or (even worse) Task.Factory.StartNew to fake asynchronous work within a request context.
For example, if you needed to search in a database (I/O), then that would be naturally asynchronous, and you should use the asynchronous APIs (e.g., EF6 has asynchronous queries):
public Task<MyAppUser> FindByNameAsync(string userName) {
return dbContext.Users.Where(x => x.Name == userName).FirstAsync();
}
If you're planning to have asynchronous APIs but for now you're just doing test/stub code, then you should use FromResult:
public Task<MyAppUser> FindByNameAsync(string userName) {
return Task.FromResult(mySearch(userName));
}

Async web calls bottlenecking and running sequencially

I have a web site which makes frequent requests to an external web service, and I'd like these calls to be async and parallel to avoid blocking and to speed up the site a bit. Basically, I have 8 widgets, each of which has to make its own web call(s).
For some reason, only the first 3 or so of them truly load async, and then the threads don't free up in time, and the rest of the widgets load sequencially. If i could get 3 of them to load in parallel, then 3 more in parallel, then 2 more in parallel, i'd be happy. So the issue is really that the threads aren't freeing up in time.
I'm guessing the answer has to do with some IIS configuration. I'm testing on a non-server OS, so maybe that's part of it.
Edit for #jon skeet:
I'm using reflection to invoke the web calls like this:
output = methodInfo.Invoke(webservice, parameters);
The widget actions (which eventually call the web service) are called via a jquery $.each() loop and the .load function (maybe this causes a bottleneck?). The widget actions are set up as async methods in an async controller.
Here is the code for one of the async methods (they are all set up like this):
public void MarketTradeWidgetAsync()
{
AsyncManager.OutstandingOperations.Increment();
//a bunch of market trade logic
//this eventually calls the web service
PlanUISetting uiSettingMarketQuotesConfig = WebSettingsProviderManager.Provider.GetMarketQuotes(System.Configuration.ConfigurationManager.AppSettings["Theme"], SessionValues<String>.GlobalPlanID, SessionValues<String>.ParticipantID, "MARKETQUOTES");
AsyncManager.OutstandingOperations.Decrement();
}
public ActionResult MarketTradeWidgetCompleted(MarketTradeTool markettradetool)
{
if (Session.IsNewSession)
return PartialView("../Error/AjaxSessionExpired");
else
{
ViewData["MarketData"] = markettradetool;
return PartialView(markettradetool);
}
}
And, like I said, these methods are called via jquery. My thinking is that since the action methods are async, they should give control back to the jquery after they get called, right?
SessionState = "readonly" for the page at hand fixed this issue. Evidently session locking was the issue.

Resources