Ключевые слова C # async и await не работают должным образом с получателем свойств

Не могли бы вы вкратце объяснить мне, почему первые две строки этого кода не выполняются параллельно? Как я могу заставить его работать параллельно?

SensorLeft и SensorRight относятся к одному и тому же классу, а Distance является его общедоступным свойством, для вычисления которого требуется некоторое время при вызове его метода get.

Что я делаю неправильно? Должен ли я сделать расчет расстояния как асинхронную функцию, чтобы быть правильным?

public async void GetDistance()
{
    await Task.Run(() => LeftDistance = SensorLeft.Distance);
    await Task.Run(() => RightDistance = SensorRight.Distance);
    Distance = RightDistance < LeftDistance ? RightDistance:LeftDistance;
}

person sirCSI    schedule 25.01.2018    source источник
comment
Когда вы await выполняете первую задачу, вы ждете ее завершения, прежде чем перейти к следующей строке кода. Сначала назначьте задачи, а затем используйте Task.WhenAll, чтобы они выполнялись одновременно.   -  person JSteward    schedule 25.01.2018
comment
async void предназначен только для обработчиков событий. Вы должны использовать async Task. await означает ожидание завершения асинхронной операции. Параллельно начинает работать Task.Run, а не await. Если вы хотите, чтобы операции выполнялись параллельно, сохраните возвращенные задачи в массиве и используйте await Task.WhenAll(tasks), чтобы дождаться их завершения.   -  person Panagiotis Kanavos    schedule 25.01.2018
comment
Кроме того, если вы не вызываете асинхронный метод, который выполняет порты завершения ввода-вывода, это не только медленнее, но и использование потоков, что может привести к еще большим проблемам с производительностью.   -  person Erik Philips    schedule 25.01.2018
comment
Помните, что await не делает ничего асинхронного. Await проверяет, завершена ли задача, и, если нет, возвращает значение, чтобы вызывающая сторона могла найти дополнительную работу. В этом случае оставшаяся часть метода превращается в завершение ожидаемая задача. Если вы думаете, что await делает что-то асинхронным, очистите свой разум от этого ошибочного убеждения сегодня же.   -  person Eric Lippert    schedule 25.01.2018


Ответы (1)


Когда компилятор встречает ключевое слово await, он автоматически запланирует задачу в планировщике задач. Операция ожидает (неблокирующим образом) завершения задачи, прежде чем продолжить выполнение остальной части блока кода.

Чтобы ваш код работал параллельно, вам нужно изменить его на

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 имеет перегрузку для возврата Task<TResult[]> Task.WhenAll<TResult[]>. и вы можете заменить свой код на

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

Однако это не очень хорошее решение. Если вы хотите, чтобы расстояние получения было действительно асинхронным, вы должны сделать асинхронный метод получения, а не обернуть его в Task.Run.

person LxL    schedule 25.01.2018
comment
Спасибо! В чем разница в том, чтобы обернуть его в Task.Run или сделать асинхронным получение? Кстати, могу ли я сделать асинхронный получатель свойств или я должен сделать это как функцию? - person sirCSI; 25.01.2018
comment
Получатель свойств не поддерживает асинхронность, вы должны создать функцию получения. Я признал, что обертывание синхронной операции в Task.Run — это самый быстрый способ сделать асинхронную операцию, но это не рекомендуется. У Стивена Тоуба MSFT есть лучшее объяснение в этом блоге /" rel="nofollow noreferrer">blogs.msdn.microsoft.com/pfxteam/2012/03/24/ - person LxL; 25.01.2018