Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Misunderstanding of async/await functions

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

After a previously question, I try to use async/await to avoid freezing UI. But each of my test is unsuccessfull.

The main function, which does a heavy work, was 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;
  }
}

A call to this function is like

if(!PopulateTV())
{
}

I try to implement the 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, as I return a bool and not Task<bool>. So I change the DoHeavyWork function :

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

This time, no error, but a warning (I use a non english version of VS, so I translate the error/warning message) :

This async method doesn't have an await operator, so it will execute as synchronous.

It's only a warning, but why do I get this message ?

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

! operator can't be used with 'System.Threading.Tasks.Task'.

Of course. But PopulateTV() return a bool (return boolResult;), even if the method declaration use Task<bool>.

Where is my error ?

like image 318
bubarnet Avatar asked Jan 23 '26 22:01

bubarnet


2 Answers

You are not actually running your heavy-lifting code in a seperate thread - async does not automatically guarantee that.

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

like image 136
fk2 Avatar answered Jan 26 '26 11:01

fk2


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

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

See this question for some more details.


However, as pointed out in the comments, this is not a clean solution. Offloading work to background threads to preserve UI responsiveness belongs to the UI code and not the API implementing the work. For a more modular solution you should implement it this way:

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;
}

See the following blog posts for more information about this:

  • Should I expose asynchronous wrappers for synchronous methods?
  • Task.Run Etiquette and Proper Usage
  • Task.Run Etiquette Examples: Don't Use Task.Run for the Wrong Thing
  • Task.Run Etiquette Examples: Don't Use Task.Run in the Implementation
like image 21
Good Night Nerd Pride Avatar answered Jan 26 '26 11:01

Good Night Nerd Pride