-5

Can you briefly explain me why the first two rows of this code are not running parallel? How could I make it work paralell?

SensorLeft and SensorRight are of the same class, and Distance is a public property of it which needs some time to be calculated when calling its get method.

What am I doing wrong? Should I make the Distance calculation as an async function instead to be right?

public async void GetDistance()
{
    await Task.Run(() => LeftDistance = SensorLeft.Distance);
    await Task.Run(() => RightDistance = SensorRight.Distance);
    Distance = RightDistance < LeftDistance ? RightDistance:LeftDistance;
}
sirCSI
  • 1
  • 2
  • When you `await` the first task you are waiting for it to finish before moving to the next line of code. Assign the tasks first then use `Task.WhenAll` to let them run at the same time. – JSteward Jan 25 '18 at 17:43
  • `async void` is only meant for event handlers.You should use `async Task`. `await` means *await* for an asynchronous operation to finish. It's `Task.Run` that starts work in parallel, not `await`. If you want the operations to run in parallel store the returned tasks in an array and use `await Task.WhenAll(tasks)` to wait for both of them to finish. – Panagiotis Kanavos Jan 25 '18 at 17:46
  • Also unless you are calling an async method that does IO Completion Ports, this is not only slower, but using threads causing possibly even more performance problems. – Erik Philips Jan 25 '18 at 17:58
  • 1
    Remember, *await does not make something asynchronous*. Await *checks to see if a task is complete, and if it is not, returns so that the caller can find more work to do.* In that case the remainder of the method is made into the completion of the awaited task. If you think that await makes something asynchronous, purge that incorrect belief from your mind today. – Eric Lippert Jan 25 '18 at 18:13

1 Answers1

-1

When the compiler encounters await keyword it will automatically schedule a task in task scheduler. The operation waits (in a non-blocking manner) for the task to complete before continue to do the rest of the code block.

To make your code run in parallel you need to modify it into

public async Task GetDistance()
{
    var leftDTask = Task.Run(() => LeftDistance = SensorLeft.Distance);
    var rightDTask= Task.Run(() => RightDistance = SensorRight.Distance);
    await Task.WhenAll(leftDTask,rightDTask);
    Distance = RightDistance < LeftDistance ? RightDistance:LeftDistance;
}

Task.WhenAll has an overload to return Task<TResult[]> Task.WhenAll<TResult[]>. and you can replace your code into

public async Task GetDistance()
{
    var leftDTask = Task.Run(() => SensorLeft.Distance);
    var rightDTask= Task.Run(() => SensorRight.Distance);
    var results= await Task.WhenAll(leftDTask,rightDTask);
    Distance = Math.Min(results[0],results[1]);
}

However, this is not a good solution. If you want the get distance truly asynchronous, you should make an asynchronous get method rather wrap it into Task.Run.

LxL
  • 1,878
  • 2
  • 20
  • 39
  • Thank you! What is the difference in wrapping it into Task.Run or making the get async? Btw can I make a property getter async or I must make it as a function? – sirCSI Jan 25 '18 at 17:58
  • The property getter does not support async, you must make a getter function. I admitted that wrapping a synchronous operation into Task.Run is a quickest way to make an asynchronous operation but it isn't recommended. Stephen Toub MSFT has a better explanation in this blog https://blogs.msdn.microsoft.com/pfxteam/2012/03/24/should-i-expose-asynchronous-wrappers-for-synchronous-methods/ – LxL Jan 25 '18 at 18:11