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

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

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.

When is using Task.Run wasteful or delusional?

I have an interface that reads/writes an object to storage. In one case the storage is a database with async methods. In the other case it's just a cookie.
I gather that its recommended to use async back along the path ending at an async call, so it seems to make sense for the interface to be async as well. But in the cookie case, I'm just setting a couple fields and sticking it in the response so there isn't any async there yet. I can wrap that bit in await Task.Run() to match the new interface but I don't know if this is advisable or if it has some negative impact on performance.
What to do?
public interface IProfileStore
{
async Task SetProfile(UserProfile profile);
}
public async Task SetProfile(UserProfile profile)
{
// Look mom, I'm needlessly async
await Task.Run(() =>
{
var cookie = new HttpCookie(AnonymousCookieName);
cookie["name"] = profile.FullName;
HttpContext.Current.Response.Cookies.Add(cookie);
});
}
You should not do that; you're just creating needless threadpool churn.
Instead, remove the async keyword from the method and simply return Task.FromResult(0) to return a synchronously-completed task
If you're performing a very short quickly completed operation then you're quite right that there is likely no need to use Task.Run to push the work to another thread. The act of scheduling the code in the thread pool is likely going to take longer than just doing it.
As for how to do that, just remove the await Task.Run that you have no need for and voila, you're all set. You have a synchronous operation that is still wrapped in a Task and so still matches the required interface.
Almost as SLaks suggests if you were doing something async but return the Task, so:
public Task SetProfile(UserProfile profile)
{
return Task.Run(() =>
{
var cookie = new HttpCookie(AnonymousCookieName);
cookie["name"] = profile.FullName;
HttpContext.Current.Response.Cookies.Add(cookie);
});
}
However as he suggests in this case:
public Task SetProfile(UserProfile profile)
{
var cookie = new HttpCookie(AnonymousCookieName);
cookie["name"] = profile.FullName;
HttpContext.Current.Response.Cookies.Add(cookie);
return Task.FromResult(null);
}
Return null as its a system cached completed Task.

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.

C# async awaitable clarification?

I've read here that :
Await examines that awaitable to see if it has already completed; if
the awaitable has already completed, then the method just continues
running (synchronously, just like a regular method).
What ?
Of course it won't be completed because it hasn't even started !
example :
public async Task DoSomethingAsync()
{
await DoSomething();
}
Here await examines the awaitable to see if it has already completed
(according to the article) , but it (DoSomething) haven't event started yet ! , so the result will always be false
It would make sence if the article was to say :
Await examines that awaitable to see if it has already completed
within x ms; (timeout)
I probably missing something here..
Consider this example:
public async Task<UserProfile> GetProfileAsync(Guid userId)
{
// First check the cache
UserProfile cached;
if (profileCache.TryGetValue(userId, out cached))
{
return cached;
}
// Nope, we'll have to ask a web service to load it...
UserProfile profile = await webService.FetchProfileAsync(userId);
profileCache[userId] = profile;
return profile;
}
Now imagine calling that within another async method:
public async Task<...> DoSomething(Guid userId)
{
// First get the profile...
UserProfile profile = await GetProfileAsync(userId);
// Now do something more useful with it...
}
It's entirely possible that the task returned by GetProfileAsync will already have completed by the time the method returns - because of the cache. Or you could be awaiting something other than the result of an async method, of course.
So no, your claim that the awaitable won't have completed by the time you await it isn't true.
There are other reasons, too. Consider this code:
public async Task<...> DoTwoThings()
{
// Start both tasks...
var firstTask = DoSomethingAsync();
var secondTask = DoSomethingElseAsync();
var firstResult = await firstTask;
var secondResult = await secondTask;
// Do something with firstResult and secondResult
}
It's possible that the second task will complete before the first one - in which case by the time you await the second task, it will have completed and you can just keep going.
await can take any Task or Task<T>, including completed tasks.
In your example, the inner DoSomething() method (that should rather be named DoSomethingAsync(), and its caller DoSomethingElseAsync()) returns a Task (or a Task<T>). That task can be a completed task fetched from somewhere else, the method is not required to start its own task.

Categories

Resources