Let's say I have this sample code
var t = Float();
...
t.Wait();
async Task Float()
{
while (LoopIsAllowed)
{
TryToComplete();
System.Threading.Thread.Sleep(500);
}
}
In this case code run synchronously and I have warning "async method lacks 'await'". I really need to run Float() async so this warning should almost always be considered. As I see it the problem here is that if I call Float()
and await it latter the application will not work as intended and it will stuck on var t = Float()
instead of t.Wait()
But I do not see any way to fix that other than like this:
async Task Float()
{
while (LoopIsAllowed)
{
TryToComplete();
await Task.Run(() => System.Threading.Thread.Sleep(500));
}
}
Does this fix have any sense? In terms of memory and processor resources is it fine to call Task.Run
or is there better way?
As I see it after the fix calling var t = Float()
will force the code to run synchronously until await Task.Run
is reached. Then parent code will continue execution until t.Wait()
. Only then it will continue to iterate through while (LoopIsAllowed)
loop. And this behavior is exactly what I need.
Is this correct?
EDIT: What should I do if I do not have any delay in my code at all? And there is no other place to await. Should I just add delay? Or should I analyze code and add Task.Run somewhere around time consuming calculations blocks?
CodePudding user response:
Never use Thread.Sleep
in async method.
use await Task.Delay();
instead of Thread.Sleep
async Task Float()
{
while (LoopIsAllowed)
{
TryToComplete();
await Task.Delay(500);
}
}
and in main method use GetAwaiter().GetResult()
instead of wait
var t = Float().GetAwaiter().GetResult();
CodePudding user response:
If your intention is to introduce parallelism, the best place to offload synchronous work to the ThreadPool
by using the Task.Run
method is the upper level possible. This means that hiding Task.Run
s deep inside method chains should generally be avoided. The reasoning is explained in this article: Should I expose asynchronous wrappers for synchronous methods? In your case the (not aptly named) Float
method does synchronous work, so it should be a synchronous method with a void
return type. You could then offload it to the ThreadPool
like this:
Task t = Task.Run(() => Float());
//...
t.Wait();
The Task.Run
is a clever little method that handles synchronous and asynchronous delegates (delegates with Task
return type) equally well. So if you decide later to improve the efficiency (regarding utilization of threads) of the Float
method by converting it to a mixed sync-async method, you can do it without changing anything in the calling site (beyond the name of the method that should now have the Async
suffix):
async Task FloatAsync()
{
while (LoopIsAllowed) // Potential code smell here. Is the LoopIsAllowed volatile?
{
TryToComplete();
await Task.Delay(500);
}
}
Task t = Task.Run(() => FloatAsync());
//...
t.Wait();