nested async methods and thread pool Asp.Net - c#

I'm building an async Web Api and after reading some articles about async/await I think I'm doing something wrong.
this is my actual code:
public async Task<IHttpActionResult> GetAccount(int id)
{
var i = await GetInstanceIdAsync(User, _db); //grabs a thread
...
}
public async static Task<int> GetInstanceIdAsync(IPrincipal user, Entities db)
{
var userManager =
new UserManager<ControliUser>(new UserStore<ControliUser>(db));
//next line grabs another thread but since it was called from an await
//it holds 2 threads, am I correct?
var u = await userManager.FindByNameAsync(user.Identity.Name);
return u == null ? 0 : u.InstanceId ?? 0;
}
So my first question is, Is this consuming 2 threads?
If the answer is yes, then I made this extension method to prevent that.
public static Task<int?> InstanceIdAsync(this Entities db, IPrincipal user)
{
var userManager = new UserManager<ControliUser>(new UserStore<ControliUser>(db));
return userManager.FindByNameAsync(user.Identity.Name).ContinueWith(t =>
{
if (t.IsCompleted && t.Result != null)
return t.Result.InstanceId;
return null;
});
}
I think this method will only consume 1 thread and reduce overhead since it saves an async method
Am I correct?

So my first question is, Is this consuming 2 threads?
No. Using async-await doesn't generate any extra thread use. On the contrary, it frees the thread while the async operation is ongoing. This means that the thread will be used until the call to FindByNameAsync, then it will be freed, only to resume once that operation is complete. Then, it will resume the operation (code after the first await) on an arbitrary thread-pool thread, while preserving the request context.
I think this method will only consume 1 thread and reduce overhead
since it saves an async method
First of all, this won't work in WebAPI. The problem is that the continuation will only execute once the first task completes. This in turn, will signal the synchronization context that there are on-finished IO operations on-going, and will cause an exception.
As previously said, the async method doesn't generate any thread-use, all it does is create a state-machine so it can invoke the continuation of your method (any calls after the first await) properly.

Related

Can I run sync code as async to gain performance? [duplicate]

This question already has answers here:
Why use async and return await, when you can return Task<T> directly?
(9 answers)
Closed 2 years ago.
I've read a bunch of forums, tutorials and blogs talking about the usage of Async/Await in C#. The more I read the more confusing it gets.
Also, people mainly talk about calling async stuff in a sync method but not calling sync stuff in an async method.
As I am a junior developer and do not have much experience with async programming I'll post a new question here and hope for some enlightenment.
Consider this:
I have a Web API endpoint that does some calculations and model building and returns some data.
public async Task<JsonResult> GetData()
{
Task<Data> stuff1Task = CalculateStuff1();
Task<Data> stuff2Task = CalculateStuff2();
Task<Data> stuff3Task = CalculateStuff3();
return Json(
new
{
stuff1 = await stuff1Task,
stuff2 = await stuff2Task,
stuff3 = await stuff3Task
}, JsonRequestBehavior.AllowGet
);
}
private async Task<Data> CalculateStuff1()
{
return await SomeAsyncCalculation();
}
private async Task<Data> CalculateStuff2()
{
return SomeSyncCalculation();
}
private async Task<Data> CalculateStuff3()
{
Task<Data> dataTask1 = SomeAsyncCalculation();
Task<Data> dataTask2 = AnotherAsyncCalculation();
Data data1 = await dataTask1;
Data data2 = await dataTask2;
Data combindedData = SyncMethodToCombineData(data1, data2);
return combindedData;
}
Why I consider mixing async and sync code is for getting better performance.
In this case lets pretend SomeAsyncCalculation(), SomeSyncCalculation() and AnotherAsyncCalculation() are pretty costly methods. My goal is to get the methods to run somewhat in parallel to gain some faster response times.
I know it is best to go "Async all the way" but lets be real, rebuilding half the project is not always a priority or a possibility.
Also I might have some integrations with other systems that do not support async operations.
This warning I get for CalculateStuff2() adds to the confusion. :
this async method lacks 'await' operators and will run synchronously
In my understanding the "async" keyword is only good for wrapping the method and allowing me to use await keyword. It also allows me to just return the data and I don't need to manage Task returning results. It also handles exceptions.
The Task<TResult> return type is what makes the method execute on a different thread (although it is not guaranteed it will execute on a different thread).
Concluding questions:
1. Will the async method that does not use await (CalculateStuff2()) run synchronously on it's own thread (if it runs on another thread because it is a Task) or will it run in the main thread of the API call, and always block it no matter what?
2. Is it bad practice to use async without await just to have a nicely wrapped task method out of the box?
You're not need for async in sync method. async generates State Machine that is a kind of redundancy in case you're not need for await.
Consider this somewhat optimized example.
public async Task<JsonResult> GetData()
{
Task<Data> stuff1Task = CalculateStuff1();
Task<Data> stuff3Task = CalculateStuff3();
Data stuff2data = CalculateStuff2(); // run sync method after launching async ones
return Json(new
{
stuff1 = await stuff1Task,
stuff2 = stuff2data,
stuff3 = await stuff3Task
}, JsonRequestBehavior.AllowGet);
}
private Task<Data> CalculateStuff1() // optimized
{
return SomeAsyncCalculation();
}
private Data CalculateStuff2()
{
return SomeSyncCalculation();
}
private async Task<Data> CalculateStuff3()
{
//use combinator to simplify the code
Data[] data = await Task.WhenAll(SomeAsyncCalculation(), AnotherAsyncCalculation());
Data combindedData = SyncMethodToCombineData(data[0], data[1]);
return combindedData;
}
Also consider to differ the CPU-bound and IO-bound operations, look at this article. There's different async approach depending on what exacly you're launching.
Direct answers
Will the async method that does not use await (CalculateStuff2()) run synchronously on it's own thread (if it runs on another thread because it is a Task) or will it run in the main thread of the API call, and always block it no matter what?
Yes, it will run synchronously on the caller Thread. If you want to run some sync method on its own Thread, use Task.Run():
Task<Data> stuff2Task = Task.Run(() => CalculateStuff2());
and then await it.
Is it bad practice to use async without await just to have a nicely wrapped task method out of the box?
Yes, it's bad practice. Redundant State Machine makes overhead which in this case is worthless.

HttpClient ReadAsAsync<IQueryable<T>> never returns

Im quite new to writing controllers for asp.net and Im trying to return IQueryable, but I cant seem to get the call for the content to return.
This is my controller:
// GET: api/RumsaRooms
[EnableQuery]
public IQueryable<RumsaRoom> GetRooms()
{
return db.Rooms;
}
and this is my client call:
public async Task<IQueryable<T>> GetAllOf<T>()
{
var typeName = typeof(T).Name;
var result = await _client.GetAsync($"api/{typeName}");
if (!result.IsSuccessStatusCode)
{
var exception = await result.Content.ReadAsStringAsync();
}
//This method never returns
var rooms = await result.Content.ReadAsAsync<IQueryable<T>>();
return rooms;
}
I have enabled multipleactiveresultsets in the connectionstring.
The StatusCode is 200.
The method that GetAllOf() looks like this:
private async Task<bool> LoadEntities()
{
var rooms = (await _rumsaClient.GetAllOf<RumsaRoom>()).ToList();
RoomsCollection = new ObservableCollection<RumsaRoom>(rooms);
return true;
}
LoadAllEntities is called in the constructor of my viewmodel.
If I change the call to this it works:
var rooms = await result.Content.ReadAsAsync<List<T>>();
Is it not possible to ReadAsAsync to a IQueryable?
Thanks
Erik
Your problem is almost certainly in this code:
LoadAllEntities is called in the constructor of my viewmodel.
I explain why this deadlock happens in detail on my blog. It doesn't have anything to do with ReadAsAsync or IQueryable. It has to do with calling Wait or Result on an asynchronous task.
In summary:
Tasks returned by async methods are only completed when that method completes.
await by default captures a "context" and uses that "context" to resume the async method.
On ASP.NET, this "context" is an instance of AspNetSynchronizationContext, which only allows one thread in at a time.
When the code calls Wait/Result, it will block the thread (which is still in the ASP.NET request context), waiting for the task to complete.
When the await is ready to resume the method, it does so in the captured context, and waits for the context to be free.
Since await cannot complete the method until the context is free, and the context is in use by a thread waiting until the method completes, you end up with a deadlock.
The proper way to solve this is to not block on asynchronous code; use await instead. This principle is called "async all the way", and is described in my MSDN article on async best practices. Since you're trying to call asynchronous code from a constructor, you may also find my blog post on async constructors helpful, which explains some alternative approaches.

How should i use async await between my business/service/application layer

Right now my methods look something like this.
ProductManager class in business
public static async Task<List<ProductItem>> GetAllProducts()
{
var context = GetMyContext();
return await context.Products.select(x =>
new ProductItem{ //create item})
.ToListAsync();
}
ProductService class in service.
public async Task<List<ProductItem>> GetAllProducts()
{
return await ProductManager.GetAllProducts();
}
ProductController in application.
public async Task<ActionResult> Index()
{
var ps = new ProductService();
var productsAsync = ps.GetAllProducts();
// Do other work.
var products = await productsAsync;
return View(products);
}
This application gets high usage,
Is this way of doing it totally wrong ?
Should I be await every method ?
Will this start a new thread every time await is called ?
This application gets high usage, Is this way of doing it totally wrong?
No; it looks good to me.
Should I be await every method?
Yes. Once you put in the first await (in ProductManager), then its callers should be awaited, and their callers awaited, and so on, up to the controller action method. This "growth" of async is entirely natural; it's called "async all the way" in my MSDN article on async best practices.
Will this start a new thread every time await is called?
No. Await is about freeing up threads, not using more threads. I have an async intro on my blog that describes how async and await work.
await simply awaits for something to complete. If you don't need the results of a task in your method, you don't need to await it. GetAllProducts should simply return the results of ToListAsync.
public static Task<List<ProductItem>> GetAllProducts()
{
var context = GetMyContext();
return context.Products
.Select(x => new ProductItem{ //create item})
.ToListAsync();
}
async/await adds a bit of overhead, since the compiler has to generate a state machine that stores the original synchronization context, waits for the awaited task to finish and then restores the original synchronization context.
Adding async/await on a method that doesn't need to process the result of the task simply adds overhead. In fact, there are some Roslyn analyzers that detect and fix this issue

Async/Await in foreach with HTTPClient

I have a webservice that loads up some plugins (dlls) and calls their Process method. One of the plugins takes a list of members and ensures that they are all included in a MailChimp list.
Here is the code that adds the users to the MailChimp group.
private async Task AddMCUsers(List<Member> _memberList)
{
using (var http = new HttpClient())
{
var creds = Convert.ToBase64String(Encoding.ASCII.GetBytes("user:password");
http.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", creds);
string memberURI = string.Format(#"{0}lists/{1}/members", _baseURI, _memberGroupId);
var jss = new JavaScriptSerializer();
foreach (var user in _memberlist)
{
var _addStatus = "";
try
{
var content = jss.Serialize(new MCPost()
{
email_address = user.Email,
status = "subscribed",
merge_fields = new MCMergeFields()
{
FNAME = user.Firstname,
LNAME = user.Lastname
}
});
using(var result = await http.PostAsync(memberURI, new StringContent(content,Encoding.UTF8, "application/json")))
{
var resultText = await result.Content.ReadAsStringAsync();
if(result.IsSuccessStatusCode)
{
_addStatus = "Success";
var _returnedUser = jss.Deserialize<MCMember>(resultText);
//Store new user's id
user.ServiceId = _returnedUser.id;
}
else
{
_addStatus = "Fail";
}
}
}
catch {
_addStatus = "Error";
}
LogEvent("Add User - " + _addStatus, string.Format("Id: {0} - {1} {2} (Account: {3}) : {4}", user.Id, user.Firstname, user.Lastname, user.AccountId, user.Email));
}
}
}
In normal procedural code, this wouldn't be a problem. However, the only Post method available on the httpClient was PostAsync. Being fairly new to the async/await stuff, I'm not sure the ramifications on the rest of my code ... particularly as it relates to my attempt to reuse the httpClient instead of instantiating a new one for each http call.
I'm not sure what happens with await when its wrapped in a foreach like I have. Will I run into issues with reusing the httpClient to make repeated calls when running asynchronously?
My other question is, what is actually going to be returned. IOW, my understanding is that await returns a Task. However, here, I'm looping through the list and making multiple calls to await PostAsync. My method returns a Task. But which task gets returned? If my calling method needs to wait for completion before moving on, what does its call look like?
private void Process()
{
//Get List
var task = AddMCUsers(list);
task.Wait();
//Subsequent processing
}
I've read that you should use Async all the way. Does this mean my calling method should look more like this?
public async Task Process()
{
//Get list
...
await AddMCUsers(list);
//Other processing
}
Thanks to whatever help you can offer on this.
In normal procedural code, this wouldn't be a problem.
The whole point of async/await is to write asynchronous code in a way that looks practically identical to "normal" synchronous code.
Being fairly new to the async/await stuff, I'm not sure the ramifications on the rest of my code ... particularly as it relates to my attempt to reuse the httpClient instead of instantiating a new one for each http call.
HttpClient was intended to be reused; in fact, it can be used for any number of calls simultaneously.
I'm not sure what happens with await when its wrapped in a foreach like I have.
One way to think of it is that await "pauses" the method until its operation completes. When the operation completes, then the method continues executing. I have an async intro that goes into more detail.
Will I run into issues with reusing the httpClient to make repeated calls when running asynchronously?
No, that's fine.
IOW, my understanding is that await returns a Task.
await takes a Task. It "unwraps" that task and returns the result of the task (if any). If the task completed with an exception, then await raises that exception.
My method returns a Task. But which task gets returned?
The Task returned from an async method is created by the async state machine. You don't have to worry about it. See my intro for more details.
If my calling method needs to wait for completion before moving on, what does its call look like? ... I've read that you should use Async all the way. Does this mean my calling method should look more like this?
Yes, it should look like your second snippet:
public async Task ProcessAsync()
{
//Get list
...
await AddMCUsers(list);
//Other processing
}
The only thing I changed was the Async suffix, which is recommended by the Task-based Asynchronous Pattern.
in your code you should be fine with reusing the HttpClient. What async / await is allow the code to release the execution thread to prevent locking a cpu thread while waiting for the web response. It also releases control back to the caller. When releasing code back to the caller it means that if your Process function does not await your AddMCUsers, Process could finish before AddMCUsers (useful in fire and forget situations to not await a method).
What async/await do not do is affect the logical flow of an individual method. When you await an async web call the execution is paused and then resumed at the same point once the web call returns. There is also thread context tracking and the code resumes in the same context (ie. UI thread or background thread depending on the parent) by default, but this can be changed if needed.
At some point in your code you may want to have a method that blocks until your async code competes and that is where you will want your Task.Wait() call to block execution. If all you use is awaits then it is possible for your program to end before your task competes. See the code example below.
class Program
{
static void Main(string[] args)
{
Task waitForMe = Task.Run(() => waitAsync());
}
static async Task waitAsync()
{
await Task.Delay(5000);
}
}
in the sample with out a Task.Wait call to block the Main method the program will end before the 5 second wait is complete. Having a main method of the following will cause the program to wait for 5 seconds before exiting:
static void Main(string[] args)
{
Task waitForMe = Task.Run(() => waitAsync());
waitForMe.Wait();
}

will Task.Run() make any difference in performance?

I have a method which calls database as shown below:
BL Method to call DAO method:
public async Task<List<Classes>> GetClassesAndAddRules(string classId)
{
var classData = await Task.Run( () => _daoClass.GetClasses(classId));
//logic for adding rule
//..................................
}
DatabaseCall in DAO:
//*below method takes 1 second approx to return*
public List<Classes> GetClasses(string id)
{
var retVal = new List<Classes>();
using (var context = new test_db_context())
{
var rows = context.GetClassesById(id);
foreach (ClassesDBComplexType row in rows)
{
retVal.Add(Mapper.Map<GetClassesByClassIdOut>(row));
}
}
return retVal;
}
Is there any performance boost just my calling the DAO method using await ?
My understanding is GetClasses() will be called on a separate thread so that it doesn't block and continue processing other stuff.
Any help is appreciated.
The code you posted won't compile. From the title of your question, I'm assuming that your call actually looks like await Task.Run(() => _daoClass.GetClasses(classId));
In that case, the use of Task.Run will make a difference in performance: it will be worse.
The point of async on the server side is to free up the request thread instead of blocking it. What you're doing with await Task.Run(...) is to free up the request thread by starting work on another thread. In other words, the Task.Run code has the same amount of work to do plus thread marshaling.

Categories

Resources