Обновление: ASP.NET Core не имеетSynchronizationContext
. Если вы используете ASP.NET Core, не имеет значения, используете вы его ConfigureAwait(false)
или нет.
Для ASP.NET "Полный" или "Классический" или что-то еще, остальная часть этого ответа все еще применяется.
Оригинальный пост (для не Core ASP.NET):
Это видео от команды ASP.NET содержит лучшую информацию об использовании async
в ASP.NET.
Я читал, что он более производительный, так как он не должен переключать контексты потока обратно в исходный контекст потока.
Это верно для приложений пользовательского интерфейса, где есть только один поток пользовательского интерфейса, с которым вы должны «синхронизироваться» обратно.
В ASP.NET ситуация немного сложнее. Когда async
метод возобновляет выполнение, он получает поток из пула потоков ASP.NET. Если вы отключите захват контекста с помощью ConfigureAwait(false)
, тогда поток просто продолжит выполнение метода напрямую. Если вы не отключите захват контекста, поток повторно введет контекст запроса и продолжит выполнение метода.
Так ConfigureAwait(false)
что не спасает вас от скачка потока в ASP.NET; это спасает вас от повторного ввода контекста запроса, но обычно это происходит очень быстро. ConfigureAwait(false)
может быть полезно, если вы пытаетесь выполнить небольшую параллельную обработку запроса, но на самом деле TPL лучше подходит для большинства этих сценариев.
Однако в ASP.NET Web Api, если ваш запрос поступает в один поток, и вы ожидаете какую-то функцию и вызываете ConfigureAwait (false), которая потенциально может перевести вас в другой поток, когда вы возвращаете конечный результат вашей функции ApiController ,
На самом деле, просто сделать это await
может сделать это. Как только ваш async
метод достигает await
, метод блокируется, но поток возвращается в пул потоков. Когда метод готов продолжить, любой поток вырывается из пула потоков и используется для возобновления метода.
Единственное отличие ConfigureAwait
в ASP.NET заключается в том, входит ли этот поток в контекст запроса при возобновлении метода.
У меня есть дополнительная справочная информация в моей статье на MSDNSynchronizationContext
и в моем async
вступительном блоге .
HttpContext.Current
передается ASP.NETSynchronizationContext
, который по умолчанию передается вамawait
, но не передаетсяContinueWith
. Ото, контекст исполнения ( в том числе ограничений безопасности) контекст упоминается в CLR с помощью C #, и это текло обаContinueWith
иawait
(даже если вы используетеConfigureAwait(false)
).ConfigureAwait
самом деле имеет смысл только когда вы ожидаете задачи , тогда какawait
действует на любое «ожидаемое». Рассматривались и другие варианты: должно ли поведение по умолчанию отбрасывать контекст в библиотеке? Или есть настройка компилятора для поведения контекста по умолчанию? Оба они были отклонены, потому что сложнее просто прочитать код и рассказать, что он делает.ConfigureAwait(false)
избегать тупиков на основеResult
/,Wait
потому что в ASP.NET вы не должны использоватьResult
/Wait
в первую очередь.Краткий ответ на ваш вопрос: Нет. Вы не должны звонить
ConfigureAwait(false)
на уровне приложения, как это.TL; DR-версия длинного ответа: если вы пишете библиотеку, в которой вы не знаете своего потребителя и не нуждаетесь в контексте синхронизации (чего не следует делать в библиотеке, я полагаю), вы должны всегда использовать
ConfigureAwait(false)
. В противном случае потребители вашей библиотеки могут столкнуться с тупиковыми ситуациями при использовании асинхронных методов в режиме блокировки. Это зависит от ситуации.Вот немного более подробное объяснение важности
ConfigureAwait
метода (цитата из моего поста в блоге):Кроме того, вот две отличные статьи для вас, которые именно для вашего вопроса:
Наконец, есть отличное короткое видео от Lucian Wischik , посвященное именно этой теме: методы асинхронной библиотеки должны учитывать использование Task.ConfigureAwait (false) .
Надеюсь это поможет.
источник
Task
складывается впечатление, что вы пытаетесь сказать, что идет по стеку, чтобы получить тоSynchronizationContext
, что неправильно. ЗначениеSynchronizationContext
перед захватом передается,Task
а затем остальная часть кода продолжается,SynchronizationContext
если значениеSynchronizationContext.Current
не равно нулю.SynchronizationContext.Current
все ясно, или что библиотека вызывается внутри,Task.Run()
а не записывается по.ConfigureAwait(false)
всей библиотеке классов?.ConfigureAwait(false)
. Возможно, авторам библиотек было бы легче, если бы это было поведение по умолчанию, но я бы предположил, что сделать правильную работу библиотеки немного сложнее, чем усложнить правильное написание приложения.Самый большой недостаток, который я обнаружил при использовании ConfigureAwait (false), заключается в том, что культура потоков возвращается к системному значению по умолчанию. Если вы настроили культуру, например ...
и вы размещаете на сервере, для которого установлена культура en-US, тогда вы обнаружите, что ConfigureAwait (false) будет называться CultureInfo.CurrentCulture вернет en-AU и после того, как вы получите en-US. т.е.
Если ваше приложение выполняет какие-либо действия, требующие особого форматирования данных, вам следует помнить об этом при использовании ConfigureAwait (false).
источник
ConfigureAwait(false)
она используется.У меня есть некоторые общие мысли о реализации
Task
:using
.ConfigureAwait
был введен в 4.5.Task
был введен в 4.0.Task.ContinueWith
они не выполняются, поскольку выяснилось, что переключение контекста стоит дорого, и по умолчанию оно отключено.У меня есть несколько постов на эту тему, но в дополнение к хорошему ответу Тагберка, я предпочитаю, чтобы вы включили все API-интерфейсы асинхронно и в идеале передавали контекст. Поскольку вы выполняете асинхронное выполнение, вы можете просто использовать продолжения вместо ожидания, поэтому не будет возникать тупиковой ситуации, поскольку в библиотеке не выполняется ожидание, и вы продолжаете работу, поэтому контекст сохраняется (например, HttpContext).
Проблема в том, что библиотека предоставляет синхронный API, но использует другой асинхронный API - поэтому вам необходимо использовать
Wait()
/Result
в своем коде.источник
Task.Dispose
если хотите; Вам просто не нужно подавляющее большинство времени. 2)Task
была введена в .NET 4.0 как часть TPL, которая не нужнаConfigureAwait
; когда ониasync
были добавлены, они использовали существующийTask
тип вместо изобретения новогоFuture
.Task
s; «контекст», контролируемыйContinueWith
- этоSynchronizationContext
илиTaskScheduler
. Эти различные контексты подробно объясняются в блоге Стивена Туба .Thread
s, но больше не с нимContinueWith()
), это затрудняет чтение вашего ответа.