Как я узнаю, что вызов асинхронного метода изменяет контекст вызывающего? - PullRequest
0 голосов
/ 13 февраля 2019

Рассмотрим этот пример:

async Task Foo()
{
    button.Text = "This is the UI context!";

    await BarA();

    button.Text = "This is still the UI context!";

    await BarB();

    button.Text = "Oh no!"; // exception (?)
}

async Task BarA()
{
    await Calculations();
}

async Task BarB()
{
    await Calculations().ConfigureAwait(false);
}

Как узнать, если вызов await BarB() изменяет контекст без чтения тела функции async Task BarB()?Мне действительно нужно точно знать, вызывает ли асинхронная функция ConfigureAwait(false) в любой момент?Или, может быть, пример неверный и нет исключения?

Ответы [ 2 ]

0 голосов
/ 13 февраля 2019

В дополнение Ответ Марка - имейте в виду, что async является подробностью реализации метода.Как или почему метод создает Task, который он возвращает вам, в значительной степени прозрачен (и поэтому async не является частью сигнатуры, не допускается в определениях интерфейса и т. Д.)

Хотя этоЭто правда, что ваш метод разделяет свой «текущий контекст» с методами, которые он вызывает, только в том случае, если эти методы, если они хотят знать текущий контекст, будут вызывать SynchronizationContext.Current.Затем они будут использовать методы на этого контекста, чтобы при необходимости вернуться к нему.Любые «изменения» в контексте обычно будут выполняться путем переключения продолжений на подходящий поток, для которого уже установлен правильный контекст .

Что эти методы не будут обычно звоните SetSynchronizationContext.Только если метод вызывает это, вам нужно беспокоиться об изменениях в «вашем» контексте.(Некоторые инфраструктурные коды могут вызывать этот метод, если их контекст синхронизации является свободным потоком, но требует других окружающих ресурсов. Они получат поток пула потоков, вызовят SetSynchronizationContext, выполнят продолжение и затем снова сбросят контекст синхронизации).

0 голосов
/ 13 февраля 2019

То, что делает BarB(), в значительной степени не имеет значения, если BarB() не нужно общаться с пользовательским интерфейсом.Важной частью здесь является await в строке:

await BarB();

это , что await, который захватывает контекст (тоже) - и согласовывает получение обратно на правильный контекст, если он обнаруживает, что продолжает с неправильного контекста.Так;если вы не напишите:

await BarB().ConfigureAwait(false);

с вами все будет в порядке.

ConfigureAwait(false) в BarB() выглядит нормально и является , вероятно, правильным, если мы предположим, чтоBarB() не нужно напрямую обновлять интерфейс или выполнять какие-либо другие операции, связанные с контекстом.

...