Это очень хороший вопрос, и понимание его является ключом к пониманию того, почему асинхронный ввод-вывод так важен.Причина, по которой новая функция асинхронности / ожидания была добавлена в C # 5.0, заключается в упрощении написания асинхронного кода.Поддержка асинхронной обработки на сервере не нова, однако она существует, поскольку ASP.NET 2.0.
Как показал Стив, при синхронной обработке каждый запрос в ASP.NET (и WCF) получает один поток изпул потоков.Проблема, которую он продемонстрировал, - это хорошо известная проблема под названием " истощение пула потоков ".Если вы выполняете синхронный ввод-вывод на вашем сервере, поток пула потоков останется заблокированным (ничего не делая) на время ввода-вывода.Поскольку существует ограничение на количество потоков в пуле потоков, под нагрузкой это может привести к ситуации, когда все потоки пула потоков блокируются в ожидании ввода-вывода, и запросы начинают помещаться в очередь, что приводит к увеличению времени отклика.Поскольку все потоки ожидают завершения ввода-вывода, вы увидите, что загрузка ЦП близка к 0% (даже несмотря на то, что время отклика идет вверх).
Что вы спрашиваете ( Почему может 'мы просто используем больший пул потоков? ) это очень хороший вопрос.Фактически, именно так большинство людей до сих пор решали проблему истощения пула потоков: просто добавьте больше потоков в пул потоков.Некоторая документация от Microsoft даже указывает, что в качестве исправления для ситуаций, когда может произойти голодание пула потоков.Это приемлемое решение, и до C # 5.0 это было гораздо проще сделать, чем переписать ваш код, чтобы он стал полностью асинхронным.
Однако есть несколько проблем с подходом:
Нет значения, которое работает во всех ситуациях : количество потоков пула потоков, которое вам понадобится, линейно зависит от продолжительности ввода-вывода и нагрузки на ваш сервер.К сожалению, задержка ввода-вывода в большинстве случаев непредсказуема.Вот пример: допустим, вы отправляете HTTP-запросы стороннему веб-сервису в приложении ASP.NET, выполнение которого занимает около 2 секунд.Вы сталкиваетесь с истощением пула потоков, поэтому вы решили увеличить размер пула потоков, скажем, до 200 потоков, и тогда он снова начнет работать нормально.Проблема в том, что, возможно, на следующей неделе у веб-службы возникнут технические проблемы, которые увеличат время отклика до 10 секунд.Внезапно истощение пула потоков вернулось, поскольку потоки блокируются в 5 раз дольше, поэтому теперь вам нужно увеличить число в 5 раз до 1000 потоков.
Масштабируемостьи производительность : Вторая проблема заключается в том, что если вы сделаете это, вы все равно будете использовать один поток на запрос.Нити являются дорогим ресурсом.Каждому управляемому потоку в .NET требуется выделение памяти для стека в 1 МБ.Для веб-страницы, выполняющей ввод-вывод, которая длится 5 секунд и при нагрузке 500 запросов в секунду, вам потребуется 2500 потоков в вашем пуле потоков, что означает 2,5 ГБ памяти для стеков потоков, которые будут бездействовать.Тогда у вас возникнет проблема переключения контекста, которая будет сильно влиять на производительность вашего компьютера (затрагивая все службы на компьютере, а не только ваше веб-приложение).Несмотря на то, что Windows неплохо справляется с игнорированием ожидающих потоков, она не предназначена для обработки такого большого количества потоков.Помните, что наибольшая эффективность достигается, когда количество запущенных потоков равно количеству логических процессоров на компьютере (обычно не более 16).
Таким образом, увеличение размера пула потоков - это решение, и люди занимаются этим уже десять лет (даже в собственных продуктах Microsoft), оно просто менее масштабируемо и эффективно с точки зрения использования памяти и ЦП, и вы всегда во власти внезапного увеличения латентности ввода-вывода, которое может вызвать голод. Вплоть до C # 5.0 сложность асинхронного кода не стоила проблем для многих людей. async / await меняет все, как сейчас, вы можете воспользоваться масштабируемостью асинхронного ввода-вывода и одновременно писать простой код.
Подробнее: http://msdn.microsoft.com/en-us/library/ff647787.aspx " Использование асинхронных вызовов для вызова веб-служб или удаленных объектов, когда есть возможность выполнить дополнительную параллельную обработку во время вызова веб-службы. По возможности избегайте синхронных (блокирование ) вызовы веб-служб, поскольку исходящие вызовы веб-служб выполняются с использованием потоков из пула потоков ASP.NET. Блокирующие вызовы уменьшают количество доступных потоков для обработки других входящих запросов."