Nano Hash - криптовалюты, майнинг, программирование

Почему асинхронный ожидание не повышает производительность?

Я смотрел это видео: https://channel9.msdn.com/Events/TechDays/Techdays-2012-the-Netherlands/2287. Поэтому я попытался реализовать использование async/await в контроллере. Итак, это в основном то, что я сделал:

 public class HomeController : Controller
    {
        private static WebClient _webClient = new WebClient();
        public async Task<ActionResult> IndexAsync()
        {
            var data = await _webClient.DownloadStringTaskAsync("http://stackoverflow.com/");
            return View("Index", (object)data);
        }
        public ActionResult Index()
        {
            var data = _webClient.DownloadString("http://stackoverflow.com/");
            return View("Index", (object)data);
        }
    }

Затем я использовал Apache Benchmark и провел два следующих теста:

ab -n 100 -c 100 http://localhost:53446/Home/index

и

ab -n 100 -c 100 http://localhost:53446/Home/indexasync

И я получил точно такую ​​же производительность (у меня 8 ядер процессора). Это почему ?


  • Какого улучшения производительности вы ожидали? 10.11.2016
  • У вас нет нескольких асинхронных операций, работающих одновременно, поэтому я не ожидаю никакого ускорения. 10.11.2016
  • Для одного запроса вы, скорее всего, увидите падение производительности. Асинхронность снижает нагрузку, позволяя обрабатывать больше одновременных запросов. 10.11.2016
  • параметр -c подразумевает 100 одновременных запросов, а -n - количество запросов, поэтому в основном я отправляю 100 одновременных запросов в свое приложение, которое будет выполнять 100 одновременных запросов к SO. 10.11.2016
  • Попробуйте загрузить страницу SO + Google. Первый (асинхронный) будет отправлять два запроса параллельно, а второй будет ждать завершения загрузки SO, прежде чем начать загрузку страницы Google. Тогда вы должны увидеть разницу. 10.11.2016
  • Каждый запрос все еще должен дождаться завершения загрузки, прежде чем он сможет продолжить. Если бы вы, скажем, выполняли некоторые вычисления одновременно с загрузкой, вы бы увидели ускорение за счет использования асинхронности, поскольку теперь вы делаете две вещи одновременно, а не последовательно. 10.11.2016
  • Эми асинхронно должна быть здесь для освобождения потоков. Итак, здесь я ожидаю, что asp.net mvc исчерпает потоки в синхронной версии и начнет ставить в очередь мои запросы, но не похоже, что он это делает. 10.11.2016
  • Я знаю, что должен делать асинхронный режим, спасибо. 10.11.2016
  • @goenning: Неправильно. Асинхронный! = параллельная обработка. Вы можете использовать Task.WhenAll для их параллельного запуска, но если вы просто ждете каждую строку, они будут выполняться последовательно. 10.11.2016

Ответы:


1

Асинхронность не связана с производительностью. Это просто категорически неправильно. Фактически, асинхронный запрос часто будет менее эффективен, чем синхронизация, просто потому, что асинхронность связана с дополнительными накладными расходами.

Причина использования асинхронности заключается в эффективном управлении ресурсами и масштабировании. Типичный процесс веб-сервера будет иметь около 1000 потоков. Это часто называют «максимальными запросами», так как один общий поток равен одному запросу. Если у вас 8-ядерный процессор, в идеале у вас должен быть процесс на ядро ​​(в IIS они называются «веб-работниками»). Таким образом, теоретически у вас будет около 8000 потоков для работы.

На самом деле это довольно много, хотя современная веб-страница потребляет больше запросов, чем думает большинство людей. Сама страница представляет собой один запрос, но на этой странице будут изображения и внешние файлы JS и CSS, все из которых генерируют запрос и часто используют AJAX для дальнейших запросов. Дело в том, что хотя 8000+ потоков все еще достаточно много для вашего пула, вы все равно можете очень быстро исчерпать их, если сервер находится под значительной нагрузкой.

Async просто дает вам передышку выше этого предела. В ситуациях, когда поток переходит в состояние ожидания, его можно вернуть в пул для обработки других запросов, пока выполняется какое-либо внешнее действие. Альтернативой является то, что поток будет просто бездействовать (синхронизироваться). Вот и все. Речь идет исключительно о том, чтобы поручить этим бездействующим потокам какую-то другую часть работы, что может означать разницу между запросами в очереди и тайм-аутом или обработкой, даже если медленно.

10.11.2016
  • Я согласен с вами, но по умолчанию Asp.Net MVC поддерживает 8 потоков (msdn.microsoft.com/en-us/library/), поэтому здесь после 8-го запроса мои 9-й и 10-й запросы должны быть намного медленнее, потому что asp.net будет подождите Xms (думаю, 500, но не уверен) перед созданием нового. 10.11.2016
  • Ваши предположения здесь неверны. При раскручивании потоков возникают некоторые накладные расходы, поэтому этот параметр существует как способ предварительной загрузки определенной суммы. Однако на самом деле не имеет значения, существуют ли потоки или созданы, и, конечно же, не имеет значения в отношении разницы между синхронизацией и асинхронностью, поскольку это должно происходить в любом случае. Только когда все доступные потоки задействованы, вы начинаете видеть разницу между синхронизацией и асинхронностью, независимо от того, как и когда они были созданы. 10.11.2016
  • Я до сих пор не понимаю, как происходит улучшение производительности видео на канале 9. Спасибо за ваше время 10.11.2016
  • Ну, я не смотрел это видео, и сейчас у меня нет на это свободного часа, так что я не могу это комментировать. 10.11.2016

  • 2

    Запуск нагрузочного теста, который исчерпывает пул потоков, трудно выполнить на локальном компьютере. Гораздо проще притвориться, что пул потоков исчерпан, искусственно ограничив его, как я делаю по сути:

    protected void Application_Start()
    {
      int workerThreads, ioThreads;
      ThreadPool.GetMaxThreads(out workerThreads, out ioThreads);
      ThreadPool.SetMaxThreads(Environment.ProcessorCount, ioThreads);
      ...
    }
    
    15.11.2016

    3

    Есть несколько причин, которые выделяются.

    Из Использование асинхронных методов в ASP.NET МВК 4

    количество потоков в пуле потоков ограничено (максимум по умолчанию для .NET 4.5 — 5000). В больших приложениях с высокой степенью параллелизма длительных запросов все доступные потоки могут быть заняты. Это состояние известно как голодание потока.

    Таким образом, выполнение 100 запросов за раз даже не приведет к голоданию ваших потоков.

    Кроме того, простой запрос GET будет выполняться очень быстро. Тест, который выполняет действие, которое занимает несколько секунд или даже минут, принесет более очевидный прирост производительности.

    10.11.2016
  • Предел очень высок, да, но, как я понял, эти 5000 потоков не добавляются в пул по умолчанию. Потоки будут добавлены, когда вы запросите больше, и это вызовет очередь запросов. 10.11.2016
  • Я только что попробовал с большим файлом (42 МБ) и все равно получил те же результаты как в асинхронном, так и в синхронном режимах. 10.11.2016
  • Улучшения будут больше связаны с масштабируемостью и памятью, чем со скоростью выполнения. Изменяется ли объем памяти между ними? Что если увеличить количество запросов до 1000 и более? В этой статье довольно хорошо объясняется, как async/await позволяет использовать гораздо меньше памяти: msdn.microsoft.com/en-us/magazine/dn802603.aspx 10.11.2016
  • Загрузка большого файла не имеет большого значения. Асинхронная часть заключается в отправке запроса и ожидании ответа сервера. Как только ваш сервер получает ответ, ему активно нужен поток. 10.11.2016
  • Действительно, я попробую с двумя тестовыми серверами. 10.11.2016
  • @remibourgarel Вы должны увидеть увеличение производительности, как вы говорите, как только синхронная версия начнет ставить потоки в очередь (поскольку на этом этапе асинхронность обеспечивает больший параллелизм). Один поток на ядро ​​— это минимальное число потоков на процесс по умолчанию — максимальное значение по умолчанию, как я полагаю, равно 25. Вместо этого попробуйте выдать 200 или около того одновременных запросов. 15.11.2016
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

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

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..