Асинхронные контроллеры в ASP.NET MVC: реальные преимущества / как их достичь?

12

Я работал над статьей об асинхронных методах контроллера в ASP.NET MVC ( http://visualstudiomagazine.com/articles/2013/07/23/async-actions-in-aspnet-mvc-4.aspx ) и думаю, Я могу упустить момент.

Рассмотрим этот метод, который я написал, который очень похож на пример из статьи:

[HttpGet]
[AsyncTimeout(8000)]
[HandleError(ExceptionType = typeof(TimeoutException), View = "TimedOut")]
public async Task<ActionResult> Index(CancellationToken cancellationToken)
{
    WidgetPageViewModel model = new WidgetPageViewModel()
    {
        toAdd = new Widget()
    };
    model.all = await _repo.GetAllAsync(cancellationToken);
    return View(model);
}

Как я понимаю, вот как все будет разворачиваться во время выполнения:

  1. Поток ASP.NET будет создан для входящего HTTP-запроса.

  2. Этот поток (предположительно выполнив некоторую необходимую предварительную работу) войдет в мой метод Index () выше.

  3. Выполнение достигнет ключевого слова «await» и запустит процесс сбора данных в другом потоке.

  4. Исходный поток «ASP.NET» вернется к коду, который вызвал мой метод-обработчик, с экземпляром класса Task в качестве возвращаемого значения.

  5. Инфраструктурный код, который вызвал мой метод-обработчик, будет продолжать работать в исходном потоке «ASP.NET», пока не достигнет точки, где ему нужно будет использовать фактический объект ActionResult (например, для визуализации страницы).

  6. Затем вызывающая сторона получит доступ к этому объекту с помощью члена Task.Result, который заставит его (т. Е. Поток «ASP.NET») ожидать поток, неявно созданный на шаге 3 выше.

Я не вижу, что это делает по сравнению с тем же, без await / async, за исключением двух вещей, которые я воспринимаю как пустяки:

  • Поток вызывающего и рабочий поток, созданные await, могут работать параллельно в течение некоторого промежутка времени (часть «до» в # 5 выше). Я догадываюсь, что период времени довольно мал. Когда инфраструктура вызывает метод контроллера, я думаю, что обычно требуется фактический ActionResult вызова контроллера, прежде чем он сможет сделать гораздо больше (если вообще что-то).

  • Существует некоторая полезная новая инфраструктура, связанная с таймаутом и отменой длительных асинхронных операций контроллера.

Предполагается, что целью добавления асинхронных методов контроллера является освобождение рабочих потоков ASP.NET для фактического ответа на HTTP-запросы. Эти темы являются конечным ресурсом. К сожалению, я не вижу, как шаблон, предложенный в статье, на самом деле служит для сохранения этих потоков. И даже если он это делает и каким-то образом снимает с себя нагрузку по обработке запроса в какой-то не-ASPP. Поток, что это делает? Могут ли потоки обрабатывать HTTP-запрос так сильно отличается от потоков в целом?

user1172763
источник
Execution will reach the "await" keyword and kick off a data acquisition process on another thread-- Не обязательно. asyncне требует другой темы ... Это продолжение. Это можно сделать, переупорядочив инструкции в том же потоке.
Роберт Харви
Более подробная информация здесь: msdn.microsoft.com/en-us/library/hh191443.aspx
Роберт Харви
«Выполнение достигнет ключевого слова await и запустит процесс сбора данных в другом потоке». Вы получили это задом наперед: ожидание, когда оно вернется. Попробуйте разделить его так, чтобы вы сохранили результат из GetAllAsync () в переменной и подождали этого, и посмотрите, станет ли он более понятным.
Эсбен Сков Педерсен

Ответы:

9

ASP.Net, который не использует параллельную библиотеку задач (TPL), ограничен в количестве запросов, которые он может обрабатывать одновременно, числом потоков в пуле потоков. ASP.Net, который использует TPL, ограничен ЦП / памятью / вводом-выводом машин, обрабатывающих запросы.

Библиотека параллельных задач (TPL) не использует потоки так, как вы, кажется, думаете. Задачи не являются потоками, они являются оболочкой для некоторой вычислительной единицы. Планировщик задач отвечает за выполнение каждой задачи в любом потоке, который не занят. Во время выполнения ожидание задачи не блокирует поток, оно просто паркует состояние выполнения, чтобы выполнить его позже.

Обычно один HTTP-запрос обрабатывается одним потоком, полностью удаляя этот поток из пула, пока не будет возвращен ответ. С TPL вы не связаны этим ограничением. Любой поступающий запрос начинает продолжение с каждой единицы вычисления, необходимой для вычисления ответа, который может быть выполнен в любом потоке в пуле. С помощью этой модели вы можете обрабатывать гораздо больше одновременных запросов, чем со стандартным ASP.Net.

mortalapeman
источник
Итак, когда поток ASP.NET возвращается в пул? Когда ключевое слово "ожидание" ударил?
user1172763
async / await + TPL позволяют компилятору разделить ваш код на независимые вычислительные блоки, которые выполняются планировщиком задач. Поток концептуально возвращается в пул, когда у планировщика задач больше нет задач, которые могут быть выполнены, и поток завершает данную ему работу.
смертный человек
Это концептуально правильный и, вероятно, полезный ответ ... однако реальность немного сложнее из-за гибкости потоков .
Джон Ву