Должны ли все мои действия с использованием IO быть асинхронными?

Когда я прочитал статью MSDN Используя асинхронные методы в ASP.NET MVC 4, я делаю вывод, что я всегда должен использовать async для ожидания Операции с привязкой к I/O.

Рассмотрим следующий код, в котором movieManager предоставляет методы async для ORM, таких как Entity Framework.

public class MovieController : Controller
{
    // fields and constructors

    public async Task<ActionResult> Index()
    {
        var movies = await movieManager.listAsync();

        return View(movies);
    }

    public async Task<ActionResult> Details(int id)
    {
        var movie = await movieManager.FindAsync(id);

        return View(movie);
    }
}
  • Будет ли это всегда давать мне лучшую масштабируемость и/или производительность?
    • Как я могу измерить это?
  • Почему это не используется в "реальном мире"?
  • Как насчет синхронизации контекста?
    • Неужели это так плохо, что я не должен использовать async-I/O в ASP.NET MVC?

Я знаю, что это много вопросов, но литература по этой теме имеет противоречивые выводы. Некоторые говорят, что вы всегда должны использовать async для зависимых от ввода-вывода задач, другие говорят, что вы не должны использовать async в приложениях ASP.NET вообще.

Ответ 1

Будет ли это всегда давать мне лучшую масштабируемость и/или производительность?

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

Как я могу измерить это?

С нагрузочным тестированием. Если вы хотите простое доказательство концепции, вы можете проверить эту суть моего.

Почему это не используется в "реальном мире" много?

Это. Асинхронные обработчики запросов до .NET 4.5 были довольно болезненны для записи, и многие компании просто бросали больше аппаратного обеспечения на проблему. Теперь, когда .NET 4.5 и async/await набирают обороты, обработка асинхронных запросов будет по-прежнему намного более распространенной.

Как насчет синхронизации контекста?

Он обрабатывается для вас ASP.NET. У меня есть async intro в моем блоге, в котором объясняется, как await будет захватывать текущий SynchronizationContext, когда вы await задаете. В этом случае это AspNetSynchronizationContext, который представляет запрос, поэтому вещи, такие как HttpContext.Current, культура и т.д., Автоматически сохраняются в пунктах await.

Неужели это так плохо, что я не должен использовать async-I/O в ASP.NET MVC?

Как правило, если вы используете .NET 4.5, вы должны использовать async для обработки любого запроса, требующего ввода-вывода. Если запрос прост (т.е. Не попадает в базу данных или вызывает другую услугу), просто держите его синхронным.

Ответ 2

Будет ли это всегда давать мне лучшую масштабируемость и/или производительность?

Вы ответили сами, вам нужно измерить и узнать. Обычно async - это что-то, что нужно добавить позже из-за сложности, что является проблемой №1 в вашей базе кода, пока у вас не будет конкретной проблемы.

Как я могу измерить это?

Создайте его в обоих направлениях, посмотрите, что быстрее (желательно для большого количества операций)

Почему это не используется в "реальном мире" много?

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

Как насчет синхронизации контекста?

Я предполагаю, что вы имеете в виду контекст ASP.NET, если так вам не нужно синхронизировать, убедитесь, что только один поток попадает в ваш контекст и общается через него.

Неужели это так плохо, что я не должен использовать async-I/O в ASP.NET MVC?

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

Ответ 3

Включение асинхронного кода в веб-сайт имеет много отрицательных сторон:

  • У вас возникнут проблемы, когда есть зависимости между частями данных, поскольку вы не можете сделать это асинхронным.
  • Асинхронная работа часто выполняется для таких вещей, как запросы API. Считаете ли вы, что вы не должны делать это на веб-странице? Если внешняя служба опускается, значит, ваш сайт. Это не масштабируется.
  • Выполнение асинхронных операций может ускорить ваш сайт в некоторых случаях, но вы в основном вносите проблемы. Вы всегда в ожидании самой медленной, и поскольку иногда ресурсы просто замедляются по какой-либо причине, это означает, что риск чего-то замедлить ваш сайт увеличивается в разном числе числа асинхронных заданий, которые вы используете. Вам придется вводить тайм-ауты для решения этих проблем, затем код обработки ошибок и т.д.
  • При масштабировании нескольких веб-серверов, поскольку загрузка ЦП становится слишком тяжелой, асинхронная работа может повредить вам. Все, что вы использовали для ввода асинхронного кода, теперь запускается одновременно, как только пользователь нажимает на ссылку, а затем уменьшается. Это касается не только загрузки процессора, но и загрузки базы данных и даже запросов API. Вы увидите очень ужасный шаблон использования во всех системных ресурсах: пики интенсивного использования, а затем снова опуститесь. Это плохо масштабируется. Синхронный код не имеет этой проблемы: задания запускаются только после выполнения другого.

Асинхронная работа для веб-сайтов - это ловушка: не туда!

Поместите свой тяжелый код в рабочий (или задание cron), который делает это до того, как пользователь попросит их. Вы будете иметь их в базе данных, и вы можете продолжать добавлять функции на свой сайт, не беспокоясь о том, чтобы запускать слишком много асинхронных заданий, а что нет.

Производительность для сайтов серьезно переоценивается. Конечно, это хорошо, если ваша страница отображается в 50 мс, но если она принимает 250 мс, люди действительно не заметят (чтобы проверить это: поместите Sleep(200) в свой код).

Ваш код станет намного более масштабируемым, если вы просто разгрузите работу в другой процесс и сделаете сайт интерфейсом только для вашей базы данных. Не делайте, чтобы ваш веб-сервер выполнял тяжелую работу, чего он не должен делать, он не масштабируется. У вас может быть сто машин, которые тратят в общей сложности 1 час процессора на веб-страницу, но, по крайней мере, он масштабируется таким образом, что страница все еще загружается за 200 мс. Удачи вам в достижении этого с помощью асинхронного кода.


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