Асинхронные контроллеры и методы

Данное руководство устарело. Актуальное руководство: Руководство по ASP.NET Core

Последнее обновление: 31.10.2015

Уже в версиях MVC 2 и MVC 3 появились асинхронные контроллеры, однако с появлением Task Parallel Library работа с асинхронными контроллерами была предельно упрощена.

Асинхронные контроллеры служат для обработки таких запросов, которые занимают или могут занять довольно продолжительное время, например, обращение к базе данных для получения большой порции данных. Применение асинхронных контроллеров позволяет приложению продолжать выполнять другие запросы, параллельно выполняя асинхронный код. А использование модификаторов async и await позволяет создавать асинхронные методы, призванные выполнять продолжительные операции без блокирования основного потока.

Чтобы понять различие между синхронными и асинхронными запросами, рассмотрим, как IIS обрабатывает входящие запросы. Веб-сервер поддерживает пул поток, которые обслуживают запросы. Когда пользователь обращается к веб-ресурсу, веб-сервер выделяет поток из пула для обслуживания данного запроса. И пока данный поток не обработает предназначенный для него запрос, другие запросы он обрабатывать не может.

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

И если обработка запроса блокируется очень долго, то IIS начинает задействовать для обслуживания других входящих запросов новые потоки. Однако есть ограничения на общее количество потоков. Когда количество потоков достигает предела, то вновь входящие запросы помещаются в очередь ожидания. Однако и тут есть ограничение на количество запросов в очереди. И когда это количество превышает предел, то IIS просто отклоняет все остальные запросы с помощью статусного кода 503 (Service Unavailable).

При асинхронной обработке поток не ждет, пока БД вернет ему данные, а обрабатывает запрос от другого пользователя. Но когда, наконец, с сетевого ресурса или БД придут нужные данные, поток возвращается к обработке ранее обрабатываемого запроса в обычном режиме.

Сравним на примере вызов синхронного и асинхронного метода:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using AsyncContollers.Models;
using System.Threading.Tasks;
using System.Data.Entity;

namespace AsyncContollers.Controllers
{
    public class HomeController : Controller
    {
        BookContext db = new BookContext();

        public ActionResult Index()
        {
            IEnumerable<Book> books = db.Books;
            ViewBag.Books = books;
            return View();
        }

        // асинхронный метод
        public async Task<ActionResult> BookList()
        {
            IEnumerable<Book> books = await db.Books.ToListAsync();
            ViewBag.Books = books;
            return View("Index");
        }
    }
}

Оба метода выполняют одну и ту же операцию - извлечение данных из БД и получают идентичные результаты. Но если первый синхронный метод Index представляет привычную для нас запись, то асинхронный метод BookList уже выглядит необычно.

Этот метод возвращает не объект ActionResult, а объект Task<ActionResult>. Task представляет асинхронную операцию, выполняющуюся продолжительное время.

Кроме того, чтобы обозначить метод как асинхронный, перед возвращаемым типом ставится ключевое слово async.

Третьим ключевым моментом является использование ключевого слова await. Оно применяется в асинхронных методах, чтобы приостановить выполнение этого метода до тех пор, пока ожидаемая задача не завершится. В нашем случае такой задачей является получение данных из БД.

Но также следует учитывать, что await используется с методами, возвращающими объект Task. Поэтому для получения данных из БД используется выражение await db.Books.ToListAsync();. Данный метод нам доступен, начиная с версии Entity Framewrok 6.

Когда следует использовать асинхронные методы? В первую очередь их предпочтительно использовать при запросах к БД, к внешнем сетевым ресурсам, однако в конечном счете, что лучше синхронность или асинхронность решает уже сам разработчик исходя из конкретной задачи.

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850