Reputation: 1266
I'm trying to solidify my understanding of async and await. I finally understood the whole thing about context switching (it's all magic). I wrote a short winform program to play around with it. Please consider the following
private async void button1_Click(object sender, EventArgs e)
{
output.Text = "start";
var intRet = await Task.Run(() => RunALot());
output.Text += " after run ";
output.Text += intRet.ToString();
}
private async Task<int> RunALot ()
{
int temp = 0;
for (int ini = 0; ini <= 40000; ini++)
{
temp += ini;
}
return temp;
}
}
I already have a Task.Run
when I'm calling RunALot.
Would I need to wrap the inside of the RunALot
yet into another Task.Run
and await
that to make this truly asynchronous? Nesting context has any performance implications - how deep can I nest context?
Upvotes: 1
Views: 1521
Reputation: 14687
You need to create the task inside the RunALot like below.
private static async Task<int> RunALotAsync()
{
// For CPU bound work use Task.Run, Alternate is Task.Factory.StartNew
return await Task.Run(() =>
{
int temp = 0;
for (int ini = 0; ini <= 40000; ini++)
{
temp += ini;
}
return temp;
});
}
Now await the RunALot on calling method
var intRet = await RunALotAsync();
Read more about correct usage of async
& await
.
Upvotes: 2
Reputation: 949
Remember that async keyword does not make your code run asynchronously. As Servy has already mentioned, RunALot() is not asynchronous method. If you want to make it async you can do something like that:
public static Task<int> RunALot()
{
return Task.Run(() =>
{
int temp = 0;
for (int ini = 0; ini <= 40000; ini++)
{
temp += ini;
}
return temp;
});
}
And this is how you can call it in button1_Click:
var intRet = await RunALot();
Upvotes: 5
Reputation: 1332
If something is synchronous, and you just want to keep your UI thread free, keep the method signature free of async task, and wrap the call with Task.Run(). You don't want your implementations to use Task.Run() to force a signature of Async, because it isn't really Asynchronous, it's a synchronous method that you want your UI to continue to be responsive while it processes. Task.Run() in this instance gives you that.
In direct connection to your sample, you don't need the async Task signature on RunAlot, because it's a CPU bound operation and isn't asynchronous by nature.
Here's some reading I encourage you to check out: http://blog.stephencleary.com/2013/11/taskrun-etiquette-examples-dont-use.html
Example of what it should be:
private async void button1_Click(object sender, EventArgs e)
{
output.Text = "start";
var intRet = await Task.Run(() => RunALot());
output.Text += " after run ";
output.Text += intRet.ToString();
}
//Removed the Async Task portion of the signature as this is CPU bound work.
private int RunALot ()
{
int temp = 0;
for (int ini = 0; ini <= 40000; ini++)
{
temp += ini;
}
return temp;
}
Upvotes: 4
Reputation: 203847
RunALot
Is not actually an asynchronous operation. You've marked it with the async
keyword, but the implementation of the method just does a bunch of work synchronously and then returns an already completed Task
at the end. Your code generates a compiler warning to tell you this.
Since RunALot
is synchronous, if you want to create a Task
that represents that synchronous work being done asynchronously on another thread. You're doing that. However, rather than having RunALot
lie and claim to be asynchronous, you should change it's signature to have it not return a Task
, so that it's clear to anyone calling it that it's not actually an asynchronous operation.
Upvotes: 5