Misunderstanding of async / await functions

I am working with C # / VS2012 / .Net4.0 / Microsoft.Bcl.async NuGet package

Following the previous question, I am trying to use async / await to avoid freezing the UI. But every one of my tests fails.

The main function doing the hard work looks like this:

public bool PopulateTV()
{
  using (WaitingForm waitingForm=new WaitingForm())
  {
    waitingForm.Show();
    bool boolResult=DoHeavyWork(); //UI is freezing, waitingForm() doesn't show correctly
    return boolResult;
  }
}

      

This function call is like

if(!PopulateTV())
{
}

      

I am trying to implement async / await

public async Task<bool> populateTV()
{
  using (WaitingForm waitingForm=new WaitingForm())
  {
    Task<bool> func=DoHeavyWork();
    bool boolResult=await func;
    return boolResult;
  }
}

public Task<bool> DoHeavyWork()
{
  //do the work
  return boolResult;
}

      

Of course, I get an error in DoHeavyWork

because I return bool

, not Task<bool>

. So I change the function DoHeavyWork

:

public async Task<bool> DoHeavyWork()
{
  //do the work
  return boolResult;
}

      

No error this time, but a warning (I'm using a non-English version of VS, so I'm translating the error / warning message):

There is no wait operator in this asynchronous method, so it will execute as synchronous.

This is only a warning, but why am I getting this message?

But this is not a big problem. When I call the parent PopulateTV () method, I want to return a bool value (if(!PopulateTV()) ...

And I get the error:

! statement cannot be used with "System.Threading.Tasks.Task".

Sure. But it PopulateTV()

returns a bool

( return boolResult;

) even if used in the method declaration Task<bool>

.

Where is my mistake?

+3


source to share


4 answers


You're not actually executing your heavy lifting code on a separate thread - asynchronously doesn't automatically guarantee this.



Try something like (await Task.Run(() => DoHeavyWork()));

+6


source


fk2's answer is correct, but you can avoid the overhead and fragility by simply returning Task<bool>

directly:

public Task<bool> DoHeavyWork()
{
    return Task.Run(() =>
    {
        return HeavyWorkReturningBool();
    });
}

      

See this question for details .


However, as pointed out in the comments, this is not a clean solution. Deploying a work on a background thread to persist the UI depends on the UI code, not the API that implements the work. For a more modular solution, you should implement it like this:



public async bool PopulateTV()
{
    using (var waitingForm = new WaitingForm())
    {
        waitingForm.Show();
        return await Task.Run(() => DoHeavyWork());
    }
}

      

DoHeavyWork

remains a regular synchronous method:

public bool DoHeavyWork()
{
    var boolResult;
    //do the work
    return boolResult;
}

      

For more information, see the following blog posts:

+4


source


But this is not a big problem. When I call the parent PopulateTV () method, I want to return a bool value (if (! PopulateTV ()) ... And I get the error:

This is if(!(await PopulateTV()))

. Wait for the result (bool) first and then evaluate it.

On the other hand, your not-so-asynchronous method is equivalent to code like this:

public Task<bool> DoHeavyWork()
{
  //do the work
  return Task.FromResult(true);
}

      

async/await

keywords are meant to work as syntactic sugar to re-write the task-based asynchronous pattern into a more readable one.

Actually, if yours DoHeavyWork

does something like this:

public async Task<bool> DoHeavyWork()
{
  await Task.Factory.StartNew(() => Thread.Sleep(10000));

  return true;
}

      

... is almost the same as writing like this:

    public Task<bool> DoHeavyWork()
    {
        return Task.Factory.StartNew
        (
             () =>
             {
                  Thread.Sleep(10000);

                  return true;
             }
        )

    }

      

You need to understand that async/await

this is just a compiler function that allows you to code elegant asynchronous code, but that doesn't mean that an async method has to be asynchronous at all. This means that an instance Task

can be expected with a keyword await

.

That is, you can implement methods with asynchronous signatures (i.e. Task MyMethod() { }

), but fake ones they return Task

generated with TaskCompletionSource<T>

:

public Task<bool> DoHeavyWork()
{
  // No async operation here. This is just a fake!
  TaskCompletionSource<bool> completion = new TaskCompletionSource<bool>();
  completion.SetResult(true);

  return completion.Task;
}

      

... and this can also be simplified with Task.FromResult<T>(T result)

, as you can check some of these pieces of response code.

So why would I need to design my APIs using the Task Based Asynchronous Pattern (TAP)?

Since the caller from your methods doesn't need to know if the method is synchronous or asynchronous. Implementing the method will solve it, but at the same time, the caller can run asynchronously if the entire method is actually asynchronous .

If you are doing the opposite (synchronization methods), your entire code flow will need to be changed if you decide to implement everything as asynchronous operations:

// I don't know if it actually async or not, I don't care. The calling method
// decides it.
bool result = await DoWorkAsync();

// I know it sync. So my code can become pure garbage if I need to make it
// synchronous since it can't be awaited and it doesn't return a Task instance!
bool result = DoWork();

      

+1


source


But it PopulateTV()

returns bool (return boolResult;) even if using the Task<bool>

.

Wrong. PopulateTV()

returns aTask<bool>

//        (return Type is here)
//           ||||||||||
//           vvvvvvvvvv
public async Task<bool> populateTV()

      

Just think of it return boolResult;

as a task return, not a method. To get the actual bool result, you need to wait for this task:

if (!(await PopulateTV()))

      

Why are you getting a warning when you declare your method like this?

public async Task<bool> DoHeavyWork()

      

Because you are using async

without await

. You don't need a keyword here async

. Everything async

does enable await

, so if you don't use await

, don't use async

. You can simply return the task:

public Task<bool> DoHeavyWork()
{
    return Task.Run<bool>(() => 
        //do the heavy work
        return boolResult;
    );
}

      

0


source







All Articles