Вопрос здесь заключается в том, должен ли я вызывать 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)
в методе обработчика событий пользовательского интерфейса, если бы мне не пришлось добавлять его по соображениям производительности.