Reputation: 101
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 ?
Upvotes: 3
Views: 329
Reputation: 8500
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:
Upvotes: 4
Reputation: 64943
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 :
It's if(!(await PopulateTV()))
. First wait for the result (bool) and later evaluate it.
In the other hand, your not that async method is equivalent to code it this way:
public Task<bool> DoHeavyWork()
{
//do the work
return Task.FromResult(true);
}
async/await
keywords are meant to work as syntactic sugar in order to re-write your task-based asynchronous pattern code into a more readable one.
Actually, if your 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 it this way:
public Task<bool> DoHeavyWork()
{
return Task.Factory.StartNew
(
() =>
{
Thread.Sleep(10000);
return true;
}
)
}
You need to understand that async/await
is just a compiler feature to let you code elegant asynchronous code, but it doesn't mean that the async method must be asynchronous at all. It means that a Task
instance can be awaited with await
keyword.
That is, you can implement methods with asynchronous signatures (i.e. Task MyMethod() { }
) but fake them returning a Task
generated by a 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 be also simplified using Task.FromResult<T>(T result)
, as you can check in some of this answer's code snippets.
Because the caller of your methods shouldn't need to know if the method is synchronous or asynchronous. Method's implementation will decide it, but at the same time the caller can work asynchronously if the whole method is actually asynchronous.
If you do the opposite (sync 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's actually async or not, I don't care. The calling method
// decides it.
bool result = await DoWorkAsync();
// I know it's 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();
Upvotes: 1
Reputation: 8904
But
PopulateTV()
return a bool (return boolResult;), even if the method declaration useTask<bool>
.
Wrong. PopulateTV()
returns a Task<bool>
// (return Type is here)
// ||||||||||
// vvvvvvvvvv
public async Task<bool> populateTV()
Just think of return boolResult;
as being the return statement of the Task, not the method. To get the actual bool result, you need to await that 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 the async
keyword here. All async
does is enable await
, so if you don't use await
, don't use async
. You can just return a Task:
public Task<bool> DoHeavyWork()
{
return Task.Run<bool>(() =>
//do the heavy work
return boolResult;
);
}
Upvotes: 0
Reputation: 749
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()));
Upvotes: 6