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

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

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

Одним из ключевых нововведений последних версий фреймворка .NET стала асинхронность. Хотя фреймворк и раньше позволял использовать асинхронные методы, но с появлением библиотеки Task Parallel Library работа с асинхронным кодом была предельно упрощена, а сам формат работы изменился. Были добавлены новые возможности по созданию асинхронных методов с использованием новых ключевых слов, таких как async и await.

При создании нового контроллера мы в настройках уже можем указать, как нам нужен контроллер - синхронный или асинхронный. По умолчанию Visual Studio добавляет в проект стандартные контроллеры, методы которых, как правило, возвращают объект ActionResult. Но если мы при добавлении контроллера в папку Controllers выберем тип MVC 5 Controller with views, using Entity Framework, то в окне настройки нового контроллера специальное поле позволит нам указать, что новый контроллер будет содержать асинхронные методы:

Асинхронные методы в ASP.NET MVC 5

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

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

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

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

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

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

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

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(), который также извлекает данные из БД, но уже в асинхронном режиме.

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

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