ТЛ; др
Да , это необходимо для того, чтобы все ваши асинхронные продолжения в коде библиотеки выполнялись в потоке пула потоков (в зависимости от SynchronizationContext / TaskScheduler используется).
Хотите узнать больше?
Task.ConfigureAwait (Boolean)
true
пытается маршалировать остаток от асинхронного метода обратно в исходный захваченный контекст
false
расписания остаток от асинхронного метода в потоке пула потоков
Рассмотрим следующий пример WPF:
WPF использует DispatcherSynchronizationContext для возобновления асинхронных продолжений в контексте пользовательского интерфейса, поскольку фоновый поток не может обновить содержимое элементов управления.
private async void Button_Click(object sender, RoutedEventArgs e)
{
logger.LogInformation(Thread.CurrentThread.IsThreadPoolThread); //false -> GUI context
await CompleteAsynchronously();
logger.LogInformation(Thread.CurrentThread.IsThreadPoolThread); //false -> GUI context
await CompleteAsynchronously().ConfigureAwait(false);
logger.LogInformation(Thread.CurrentThread.IsThreadPoolThread); //true
}
private async Task CompleteAsynchronously()
{
logger.LogInformation(Thread.CurrentThread.IsThreadPoolThread); //false -> GUI context
await Task.Delay(TimeSpan.FromMilliseconds(100)).ConfigureAwait(false);
logger.LogInformation(Thread.CurrentThread.IsThreadPoolThread); //true
}
Здесь вы видите, что флаг continueOnCapturedContext
вызванного метода не влияет на вызывающего. Тем не менее, вызываемый метод выполняется (или, по крайней мере, начинает выполняться) в потоке, в котором запущен вызывающий объект, конечно.
Однако захват текущего контекста (либо текущего SynchronizationContext
; если ноль, то текущего TaskScheduler
) происходит только тогда, когда ожидается незавершенное задание. Если задание завершается синхронно, continueOnCapturedContext
не имеет никакого эффекта, а остальная часть метода продолжает работать синхронно в текущем потоке.
private async void Button_Click(object sender, RoutedEventArgs e)
{
logger.LogInformation(Thread.CurrentThread.IsThreadPoolThread); //false -> GUI context
await CompleteSynchronously().ConfigureAwait(false);
logger.LogInformation(Thread.CurrentThread.IsThreadPoolThread); //false -> GUI context
}
private async Task CompleteSynchronously()
{
await Task.Delay(0);
}
Таким образом, в коде вашей библиотеки (при условии, что вам никогда не требуется контекст), вы всегда должны использовать ConfigureAwait(false)
, чтобы гарантировать, что для асинхронных продолжений не захватывается контекст, независимо от того, как платформа вызывает ваши сборки (например, WPF, ASP). .NET Core, консоль, ...).
Подробнее см. Рекомендации по асинхронному программированию (ia ConfigureAwait
) в этой статье MSDN Magazine от Stephen Cleary .