Zuzlx
Zuzlx

Reputation: 1266

Turning a method to awaitable

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

Answers (4)

vendettamit
vendettamit

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

Alex G.
Alex G.

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

davidallyoung
davidallyoung

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

Servy
Servy

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

Related Questions