Ключевое слово C# await вызывает блокировку вызова функции? - PullRequest
11 голосов
/ 08 мая 2020

Я пытаюсь понять, как asyn c и await работают в C#.

Рассмотрим два фрагмента ниже:

var appIdTask = GetAppIdAsync();
var clientSecretTask = GetClientSecretAsync();
var appId = await appIdTask;
var clientSecret = await clientSecretTask;
Execute(appId, clientSecret);

и

var appId = await GetAppIdAsync();
var clientSecret = await GetClientSecretAsync();
Execute(appId, clientSecret);

Эти два фрагмента имеют разные значения. Правильно?

Первый будет выполнять вызовы Get параллельно, а второй - последовательно?

Насколько я понимаю, ключевое слово await в первом вызове блокирует выполнение на второй звонок.

Ответы [ 3 ]

10 голосов
/ 08 мая 2020

Он не «блокируется» в традиционном смысле «остановка текущего потока в текущем состоянии до тех пор, пока не будет получен какой-либо сигнал» (одна из основных целей asyn c - увеличить повсюду, позволяя более эффективное использование потоков пула, потому что не все они сидели в ожидании ввода-вывода), но да: если метод сообщает, что он не завершен, выполнение будет приостановлено await и возобновлено (вполне вероятно, другой общий поток), когда доступен результат asyn c.

Итак, да, семантически это приводит к тому, что эти две вещи не выполняются одновременно (обратите внимание, что это применимо, только если первый вызов действительно асинхронный).

Обратите внимание, что многие API не ожидают нескольких одновременных асинхронных c операций и в первом примере будут иметь неопределенное поведение.

3 голосов
/ 08 мая 2020

Одно важное правило, касающееся async / awaits, заключается в том, что метод с модификатором async будет работать синхронно, пока не дойдет до первой незавершенной задачи.

Asyn c - это не параллелизм, а асинхронность. Это не основано на том факте, что метод async, а на состоянии возвращаемого Task.

Я приглашаю вас взглянуть на этот пост , и его пример кода .

1 голос
/ 08 мая 2020

Итак, в первом фрагменте:


var appIdTask = GetAppIdAsync(); // here we are starting the execution of GetAppId on another thread, no "blocking" the main one
var clientSecretTask = GetClientSecretAsync(); // instantly after starting previous method, run GetClientSecrent on yet another thread
// at this point there are 2 parallel executions on different threads happening
var appId = await appIdTask; // wait until GetAppId has finished and assign the result to appId variable
var clientSecret = await clientSecretTask; // wait until GetClientSecret has finished and assign the result to clientSecret variable
Execute(appId, clientSecret);

И втором фрагменте:

var appId = await GetAppIdAsync(); // start executing GetAppId on different thread (not blocking the main one), and return once it has been completed and assign the result to appId variable
// at this point GetAppIdAsync is completed
var clientSecret = await GetClientSecretAsync(); // start executing GetClientSecret on different thread (not blocking the main one), and return once it has been completed and assign the result to appId clientSecret 
// at this point GetClientSecretAsync is completed
Execute(appId, clientSecret);

Если вам нужно запускать несколько вызовов параллельно, я рекомендую использовать Task. WhenAll

...