Это правильный способ использования ConfigureAwait (false)? - PullRequest
0 голосов
/ 18 февраля 2020

Я создаю приложение WPF и вызываю это пользовательское событие. Вопрос в том, должен ли я звонить ConfigureAwait(false) везде? Как вы видите сейчас, я звоню 2 раза. Или даже 3 раза при втором подходе с двойным ConfigureAwait(false) в одной строке.

// First approach
void RaiseProcessEvent(object sender, EventArgs e)
{
    Task.Run(async () => await APIManager.GetInstance.ProcessMethod()).ConfigureAwait(false);
}

// Second approach
void RaiseProcessEvent(object sender, EventArgs e)
{
    Task.Run(async () => await APIManager.GetInstance.ProcessMethod().ConfigureAwait(false)).ConfigureAwait(false);
}

// This function is in a singleton class
public async Task ProcessMethod()
{
    var result = await GetInstance.GetFinalResultFromHttpClientAsync().ConfigureAwait(false);     
}

Ответы [ 2 ]

4 голосов
/ 18 февраля 2020

Вопрос здесь заключается в том, должен ли я вызывать ConfigureAwait (false) везде?

Вообще говоря, ConfigureAwait(false) следует использовать, если метод не требует возобновления при его вызывающий контекст . Решение о том, использовать или нет ConfigureAwait(false), должно приниматься для каждого метода отдельно или должно использоваться для каждого await в этом методе, или его не следует использовать для каждого await в этом методе.

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

как вы можете видеть теперь, когда я звоню 2 раза. или даже 3 раза при втором подходе с двойным конфигурированием (false) в одной строке.

В этих случаях ConfigureAwait(false) не имеет смысла. И вот почему:

//first approach
Task.Run(async () => await APIManager.GetInstance.ProcessMethod()).ConfigureAwait(false);

ConfigureAwait настраивает await. Это не настраивает задачу. Поскольку задание, возвращаемое из Task.Run, никогда не await ed, ConfigureAwait ничего не делает.

//second approach
Task.Run(async () => await APIManager.GetInstance.ProcessMethod().ConfigureAwait(false)).ConfigureAwait(false);

false часть ConfigureAwait(false) предназначена для параметра continueOnCapturedContext. Поэтому ConfigureAwait(false) говорит, что «этот метод не должен продолжаться в захваченном контексте». Но в этом случае делегат async запускается в пуле потоков (это то, что делает Task.Run), поэтому вы знаете , что в любом случае нет контекста для захвата.

Сторона примечание 1: при использовании Task.Run для вызова асинхронного метода обычно исключают ключевые слова async и await . Например: Task.Run(() => APIManager.GetInstance.ProcessMethod());. Таким образом, вопрос ConfigureAwait(false) в любом случае становится спорным, потому что await больше нет.

Примечание 2: Отмена задачи, возвращенной из Task.Run, означает, что код выполняет команду «забей и забудь», что почти всегда ужасная ошибка Среди прочего это означает, что любые исключения молча проглатываются. Почти всегда лучше использовать await:

async void RaiseProcessEvent(object sender, EventArgs e)
{
  await Task.Run(() => APIManager.GetInstance.ProcessMethod());
}

Теперь для задачи, возвращенной из Task.Run, есть await, поэтому уместно задать вопрос на этом этапе: если это await использовать ConfigureAwait(false)? Здесь мнения могут отличаться, но я бы сказал, что нет, поскольку это явно код уровня приложения (обработчик событий пользовательского интерфейса), и большинство разработчиков считают, что код, выполняющий обработчик событий, будет находиться в потоке пользовательского интерфейса (даже если существует * 1064). * ранее в этом методе). Так что для максимальной ремонтопригодности я бы не использовал ConfigureAwait(false) в методе обработчика событий пользовательского интерфейса, если бы мне не пришлось добавлять его по соображениям производительности.

2 голосов
/ 18 февраля 2020

Добро пожаловать в SO!

Если вы пишете код приложения, вам, вероятно, вообще не следует его использовать. Об этом много говорится в FAQ по ConfigureAwait на MSDN.

TL; DR:

используйте ConfigureAwait (false), если вы пишете общие- код библиотеки / app-model-agnosti c, а в противном случае - нет.

Тем не менее, это немного сложный топи c, так что я уверен, что будет много других здесь, которые не согласятся. Я написал несколько чрезвычайно сложных многозадачных приложений WPF, и я не могу вспомнить ни одного случая, когда мне действительно нужно было использовать его в коде приложения.

...