Asp.net SynchronizationContext блокирует HttpApplication для продолжения async?

Этот комментарий от Стивен Клири говорит следующее:

AspNetSynchronizationContext - самая странная реализация. Он рассматривает Post как синхронный, а не асинхронный, а использует блокировку для выполнения своих делегатов по одному за раз.

Аналогично, статья, которую он написал в контекстах синхронизации и связанная с этим комментарием, предлагает:

Концептуально контекст AspNetSynchronizationContext является сложным. Во время жизни асинхронной страницы контекст начинается только с одного потока из пула потоков ASP.NET. После запуска асинхронных запросов контекст не содержит потоков. По завершении асинхронных запросов потоки потоков, выполняющие свои процедуры завершения, входят в контекст. Это могут быть те же потоки, которые инициировали запросы, но, скорее всего, были бы потоками, которые были бы свободными в момент завершения операций.

Если несколько операций завершаются сразу для одного и того же приложения, AspNetSynchronizationContext гарантирует, что они будут выполнять одно за раз. Они могут выполняться в любом потоке, но этот поток будет иметь личность и культуру исходной страницы.

Копающий рефлектор, похоже, подтверждает это, поскольку он блокирует HttpApplication при вызове любого обратного вызова.

Блокировка объекта приложения кажется пугающим. Итак, мой первый вопрос: означает ли это, что сегодня все асинхронные доработки для всего приложения выполняются по одному за раз, даже те, которые возникли из отдельных запросов на отдельные потоки с отдельными HttpContexts? Разве это не было бы огромным узким местом для любых приложений, которые на 100% используют асинхронные страницы (или асинхронные контроллеры в MVC)? Если нет, почему бы и нет? Что мне не хватает?

Кроме того, в .NET 4.5 он выглядит как новый AspNetSynchronizationContext, а старый переименован LegacyAspNetSynchronizationContext и используется только в том случае, если новый параметр приложения UseTaskFriendlySynchronizationContext не установлен. Итак, вопрос № 2: изменилось ли это изменение в новой реализации? В противном случае я предполагаю, что с помощью нового асинхронного/ждущего завершения маршалинга завершения через контекст синхронизации этот вид узкого места будет замечен гораздо чаще в будущем.

Ответ на этот пост форума (связанный с SO answer здесь) предполагает, что что-то принципиально изменилось здесь, но я хочу четко понимать, что это такое и какие улучшения поведения улучшились, поскольку у нас есть приложение .NET 4 MVC 3, которое представляет собой почти 100% асинхронные действия, вызывающие вызовы веб-сервисов.

Ответ 1

Позвольте мне ответить на ваш первый вопрос. В вашем предположении вы не учитывали тот факт, что отдельные запросы ASP.NET обрабатываются разными объектами HttpApplication. Объекты HttpApplication хранятся в пуле. Как только вы запрашиваете страницу, объект приложения извлекается из пула и принадлежит запросу до его завершения. Итак, мой ответ на ваш вопрос:

все асинхронные доработки для всего приложения выполняются по одному, даже те, которые возникли из отдельных запросов в отдельных потоках с отдельными HttpContexts

: Нет, они не

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