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

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.

Related

How should we use async await? [duplicate]

This question already has answers here:
Why use async and return await, when you can return Task<T> directly?
(9 answers)
How and when to use ‘async’ and ‘await’
(25 answers)
Closed 3 years ago.
I was looking at how to use async await, but I do not quite get it when we have multiple methods invoking each other. Should we always use await or should we only use await when we are actually ready to use the result?
So for example should we do it like this:
async Task<string[]> FooAsync()
{
var info = await Func1();
return info.split('.');
}
async Task<string> Func1()
{
return await Func2();
}
async Task<string> Func2()
{
return await tcpClient.ReadStringAsync();
}
Or like this:
async Task<string[]> FooAsync()
{
var info = await Func1();
return info.split('.');
}
Task<string> Func1()
{
return Func2();
}
Task<string> Func2()
{
return tcpClient.ReadStringAsync();
}
Per example 1, should we always use await in every method?
Or
Per example 2 should we only use await on the top-most method when we start using the result?
Every-time you call await it creates a lump of code to bundle up variables, captures the synchronization context (if applicable) and create a continuation into an IAsyncStateMachine.
Essentially, returning a Task without the async keyword will give you a small run-time efficiency and save you a bunch of CIL. Do note that the Async feature in .NET also has many optimizations already. Also note (and importantly) that returning a Task in a using statement will likely throw an Already Disposed Exception.
You can compare the CIL and plumbing differences here
Forwarded Task
Async Method
So if your method is just forwarding a Task and not wanting anything from it, you could easily just drop the async keyword and return the Task directly.
More-so, there are times when we do more than just forwarding and there is branching involved. This is where, Task.FromResult and Task.CompletedTask come into play to help deal with the logic of what may arise in a method. I.e If you want to give a result (there and then), or return a Task that is completed (respectively).
Lastly, the Async and Await Pattern has subtle differences when dealing with Exceptions. If you are returning a Task, you can use Task.FromException<T> to pop any exception on the the returned Task like an async method would normally do.
Nonsensical example
public Task<int> DoSomethingAsync(int someValue)
{
try
{
if (someValue == 1)
return Task.FromResult(3); // Return a completed task
return MyAsyncMethod(); // Return a task
}
catch (Exception e)
{
return Task.FromException<int>(e); // Place exception on the task
}
}
In short, if you don't quite understand what is going on, just await it; the overhead will be minimal. However, if you understand the subtitles of how to return a task result, a completed task, placing an exception on a task, or just forwarding. You can save your self some CIL and give your code a small performance gain by dropping the async keyword returning a task directly and bypassing the IAsyncStateMachine.
At about this time, I would look up the Stack Overflow user and author Stephen Cleary, and Mr. Parallel Stephen Toub. They have a plethora of blogs and books dedicated solely to the Async and Await Pattern, all the pitfalls, coding etiquette and lots more information you will surely find interesting.
Both options are legit and each option has own scenarios where it is more effective then another.
Of course always use await when you want to handle result of the asynchronous method or handle possible exception in current method
public async Task Execute()
{
try
{
await RunAsync();
}
catch (Exception ex)
{
// Handle thrown exception
}
}
If you don't use result of asynchronous method in current method - return the Task. This approach will delay state machine creation to the caller or where ever final task will be awaited. As pointed in the comments can make execution little bit more effective.
But there are scenarios where you must await for the task, even you do nothing with result and don't want handle possible exceptions
public Task<Entity> GetEntity(int id)
{
using (var context = _contextFactory.Create())
{
return context.Entities.FindAsync(id);
}
}
In the scenario above, FindAsync can return not completed task and this task will be returned straight away to the caller and dispose context object created within using statement.
Later when caller will "await" for the task exception will be thrown because it will try to use already disposed object(context).
public async Task<Entity> GetEntity(int id)
{
using (var context = _contextFactory.Create())
{
return await context.Entities.FindAsync(id);
}
}
And traditionally answers about Async Await must include link to Stephen Cleary's blog
Eliding Async and Await
Await is a sequencing feature which allows the caller to receive the result of an async method and do something with it. If you do not need to process the result of an async function, you do not have to await it.
In your example Func1() and Func2() do no process the return values of the called async functions, so it is fine not to await them.
When you use await the code will wait for the async function to finish. This should be done when you need a value from an async function, like this case:
int salary = await CalculateSalary();
...
async Task<int> CalculateSalary()
{
//Start high cpu usage task
...
//End high cpu usage task
return salary;
}
If you hadn't use the the await this would happen:
int salary = CalculateSalary().Result;
...
async Task<int> CalculateSalary()
{
//Start high cpu usage task
... //In some line of code the function finishes returning null because we didn't wait the function to finish
return salary; //This never runs
}
Await means, wait this async function to finish.
Use it to your needs, your case 1 and 2 would produce the same result, as long as you await when you assign the info value the code will be safe.
Source: https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/index
I believe the 2nd one will do because await is expecting a return value.
Since it is waiting for the Func1() to return a value, Func1() is already executing Func2() which is returning a value.

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

blocking main thread on async/await

I am trying to make my base repository class asynchronous and I am running into some trouble. I am using Dapper ORM in my C# application.
Base method
protected async Task<List<T>> Read<T>(CommandDefinition cmd) {
using(SqlConnection myCon = new SqlConnection(Config.DBConnection)) {
await myCon.OpenAsync();
IEnumerable<T> results = await myCon.QueryAsync<T>(cmd);
List<T> retVal = results.ToList();
myCon.Close();
return retVal;
}
}
Calling method
public List<Category> GetAllActiveCategories(Guid siteGuid) {
return base.Read<Category>(SPNAME_GETALLACTIVE, siteGuid).Result;
}
Everything looks in order to me. I have the method declaration decorated with the async keyword. I am awaiting on asynchronous methods.
The problem that I am having is that the thread blocks on await myCon.OpenAsync();. This is my first attempt at using async and await, so I am sure that I am doing something wrong, but it is not obvious. Please help!
The posted Read code is fine. The issue is in the consuming code. It's common to get a deadlock with async if you call Wait() or Result on the returned Task or its antecedent Task up in the call chain.
As always in these cases, the general advice applies: don't block on async code. Once you start using async/await, you should be using async/await throughout your entire call chain.
So, your calling method becomes
public Task<List<Category>> GetAllActiveCategoriesAsync(Guid siteGuid) {
return base.Read<Category>(SPNAME_GETALLACTIVE, siteGuid);
}
... or
public async Task<List<Category>> GetAllActiveCategoriesAsync(Guid siteGuid) {
List<Category> result = await base.Read<Category>(SPNAME_GETALLACTIVE, siteGuid);
// Do something.
return result;
}
The culprit is:
return base.Read<Category>(SPNAME_GETALLACTIVE, siteGuid).Result;
As Kirill noted, any time you use .Wait() or .Result on a Task, you are blocking synchronously. What you need to do is this:
public Task<List<Category>> GetAllActiveCategories(Guid siteGuid) {
return base.Read<Category>(SPNAME_GETALLACTIVE, siteGuid);
}
This will return a Task to the calling method of this method, and so on... it has to be async "all the way up".
If the top-level consumer of this code is ASP.NET, you're fine. Just return a Task<IActionResult> (or the appropriate return type wrapped in a Task) and the framework will sort out the awaiting for you.
If you're writing a console application or otherwise can't make it "async all the way up", you'll have to either block on .Result or make your method async void and use await. Neither one is a great solution, sadly. Async/await is pretty aggressive in the sense that you really do have to use it throughout your stack.

Async Await Few Confusions

As experiencing the new async & Await features of 4.5 I want to clear some confusions before going any further. I have been reading different article and also different question on SO and it help me undertands how Async and Await works. I will just try to put my understanding and confusions here and will appreciate if someone code educate me and other people who are looking for same things. I am discussing this in very simple wordings.
So Async is used so that compiler know that method marked by Async contains Await operation (Long operation). Latest framework contains different new builtin methods for Async Operations.
The builtin Async functions like connection.OpenAsync, ExecuteScalarAsync etc are used with Await keyword. I don't know the inner working of these Async Methods but my strong guess is that under the hood they are using Tasks.
Can I make this as general rule that Await will be with any method which implements Task. So if I need to create my own method which is performing long operation then will I create it as Task and when it is called I will use Await Keyword with it?
Second most important thing is that what is the rule of thumb of creating a method as Async or creating it as task. For example,
public void SampleMain()
{
for (int i = 1; i <= 100; i++)
{
DataTable dt = ReadData(int id);
}
}
public DataTable ReadData(int id)
{
DataTable resultDT = new DataTable();
DataTable dt1 = new DataTable();
// Do Operation to Fill DataTable from first connection string
adapter.Fill(dt1);
DataTable dt2 = new DataTable();
// Do Operation to Fill DataTable from first connection string
adapter.Fill(dt2);
// Code for combining datatable and returning the resulting datatable
// Combine DataTables
return resultDT;
}
public string GetPrimaryConnectionString()
{
// Retrieve connection string from some file io operations
return "some primary connection string";
}
public string GetSecondaryConnectionString()
{
// Retrieve connection string from some file io operations
return "some secondaryconnection string";
}
Now this is a very simple scenario that I have created based on some real world application I worked in past. So I was just wondering how to make this whole process Async.
Should I make GetPrimaryConnectionString and GetSecondaryConnectionString as Tasks and Await them in ReadData. Will ReadData be also a Task? How to call ReadData in the SampleMain function?
Another way could be to create a Task for ReadData in SampleMain and run that Task and skip converting other methods as Task. Is this the good approach? Will it be truly Asynchronous?
So Async is used so that compiler know that method marked by Async
contains Await operation
The async is used so that the compiler will have an indication to create a state-machine out of the method. An async method can have no await, and still work, though it will execute completely synchronously.
The builtin Async functions like connection.OpenAsync,
ExecuteScalarAsync etc are used with Await keyword. I don't know the
inner working of these Async Methods but my strong guess is that under
the hood they are using Tasks.
Task is a promise of work to be completed in the future. There are a couple of ways to create a Task. But, Task isn't the only thing that can be represent an asynchronous operation. You can create an awaitable yourself if you wanted, all it needs it to implement a GetAwaiter method which returns a type implementing INotifyCompletion.
If you want to know how a method is implemented in the framework, you can view the source. In this particular case, they use TaskCompletionSource<T>.
Should I make GetPrimaryConnectionString and
GetSecondaryConnectionString as Tasks and Await them in ReadData. Will
ReadData be also a Task? How to call ReadData in the SampleMain
function?
There is nothing inherently asynchronous about retrieving a connection string. You usually (not always) use async-await with naturally async IO operations. In this particular case, the only actual async operation is ReadData, and if you want to make it asynchronous, you can use SqlDataReader, which exposes async methods.
An example, taken from the ADO.NET teams blog:
public static async Task<Product> GetProductAndReviewsAsync(
int productID, int reviewsToGet)
{
using (SqlConnection connection = new SqlConnection(ConnectionString))
{
await connection.OpenAsync();
const string commandString = GetProductByIdCommand + ";"
+ GetProductReviewsPagedById;
using (SqlCommand command = new SqlCommand(commandString, connection))
{
command.Parameters.AddWithValue("productid", productID);
command.Parameters.AddWithValue("reviewStart", 0);
command.Parameters.AddWithValue("reviewCount", reviewsToGet);
using (SqlDataReader reader = await command.ExecuteReaderAsync())
{
if (await reader.ReadAsync())
{
Product product = GetProductFromReader(reader, productID);
if (await reader.NextResultAsync())
{
List<Review> allReviews = new List<Review>();
while (await reader.ReadAsync())
{
Review review = GetReviewFromReader(reader);
allReviews.Add(review);
}
product.Reviews = allReviews.AsReadOnly();
return product;
}
else
{
throw new InvalidOperationException(
"Query to server failed to return list of reviews");
}
}
else
{
return null;
}
}
}
}
}
how to make this whole process Async
If there are asynchronous versions of adapter.Fill, then simply await for it in ReadData, which in turn also become async and you can await for it in the caller method:
// in async button click event
button.Enabled = false;
var dt = await ReadData(int id);
button.Enabled = true;
... // do something with dt
public async Task<DataTable> ReadData(int id)
{
...
var job1 = adapter.AsyncFill(dt1);
var job2 = adapter.Fill(dt2);
// wait for all of them to finish
Task.WaitAll(new[] {job1, job2});
...
return Task.FromResult(resultDT); // dump approach
}
If there are no asynchronous version then you have to create them (by using Task):
// in async button click event
button.Enabled = false;
// run synchronous task asynchronously
var dt = await Task.Run(() => ReadData(int id));
button.Enabled = true;
... // do something with dt
async/await shines when it comes to UI, otherwise (if no UI is involved) just create task and run synchronous operation there.
The only reason to use async-await is if your main thread might do something useful while another thread is doing the length operation. If the main thread would start the other thread and only wait for the other thread to finish, it is better to let the main thread do the action.
One of the things a main thread quite often does is keep the UI responsive.
You are right, under the hood async-await uses Task, hence you see that an async function returns a Task.
The rules:
If a function would return void, the async version returns Task. If the function would return TResult, the async version should return Task<TResult>.
There is one exception: the async event handler returns void.
The return value of await Task is void. The return value of await Task<TResult> is TResult.
Only async functions can call other async functions.
If you have a non-async function you can still use the async function. However you cannot use await. Use the Task return value of the async function and the System.Threading.Tasks.Task methods to wait for the results.
If you have an async function and want to start a non-async function in a separate thread, use:
private int SlowCalculation(int a, int b)
{
System.Threading.Thread.Sleep(TimeSpan.FromSeconds(5));
return a + b;
}
private async Task CalculateAsync(int a, int b)
{
Task myTask = Task.Run( () => SlowCalculation(a, b);
// while SlowCalcuation is calculating slowly, do other useful things
// after a while you need the answer
int sum = await myTask;
return sum;
}
See that the return of await Task<int> is int.
Some people used to use functions like Task.ContinueWith. Because of the await statement that is not needed anymore. Await makes sure that the task is finished. The statement after the await is what you'd normally do in the ContinueWith.
In Task.ContinueWith you could say: "do this only if the task failed". The async-await equivalent for this is try-catch.
Remember: if your thread has nothing useful to do (like keeping your UI responsive), don't use async-await
Starting several tasks in async-await and waiting for them to finish is done as follows:
private async Task MyAsyncFunction(...)
{
var tasks = new List<Task<int>>();
for (int i=0; i<10; ++i)
{
tasks.Add(CalculateAsync(i, 2*i);
}
// while all ten tasks are slowly calculating do something useful
// after a while you need the answer, await for all tasks to complete:
await Task.WhenAll(tasks);
// the result is in Task.Result:
if (task[3].Result < 5) {...}
}
The async-await version of Task.Waitall is Task.WhenAll. WhenAll returns a Task instead of void, so you can await for it. The main thread remains responsive even while awaiting.
The main thread is not the case when using Task.WaitAll, because you don't await.

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.

Categories

Resources