• Кто может разжевать асинхронные контроллеры?

    @khimalex
    Виктор П.,
    У меня не укладывается в голове, как поток может освободить ресурсы и вернуться в пул.

    Представьте себе очередь к врачу:

    В синхронном режиме врач с пациентом может его проконсультировать и отпустить, а может его проконсультировать и вместе с ним пойти на дополнительные исследования. УЗИ, допустим, и ждёт там, пока ему его сделают, простаивает и ничего полезного не делает. В это время, пока он ходит с пациентом 1 и ждёт, пришёл пациент 2 и этот пациент не получает консультацию, пока не обслужится 1й пациент.

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

    Так вот, асинхронный режим - это упрощённейшее описание TPL.
    В этой истории врачи - это пул потоков. Размер, обычно, по количеству ядер процессора, вроде как. При этом каждый врач - это уже созданный заранее поток ОС.
    Асинхронность в том, что врачи гоняют пациентов из кабинета в кабинет, а история болезни - это контекст потока и совсем не обязательно, что пациент после УЗИ попадёт к тому же врачу или другому, всё зависит от очереди, свободности врача и пр.

    Когда у нас заканчиваются врачи, то увеличение пула потоков - это добавление нового врача, но т.к. вы не можете увеличить количество ядер, то это как если бы на трёх врачей было только два кабинета.
    Потоки ОС - это более низкоуровневые "потоки". Это уже распределение ресурсов ядер процессора - освобождение кабинетов для тех кому они нужны да ещё и очень-очень быстро, а это переключение контекста потоков ОС (это отличается от контекста TPL).

    А дальше аналитика:
    Пул потоков вы увеличили, а ядра - не можете, то ОС начинает часто переключать свои контексты на выполнение ваших задач, что не хорошо.

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

    А вот при большом количестве пациентов асинхронность выигрывает - т.к., условно, возьмём 11 пациентов и одному нужно УЗИ. Пациент лечится за 1 секунду, кабинет УЗИ работает 10 секунд, если врач ходит с пациентом, то он тратит на УЗИ 10 секунд+1 секунду работа с пациентом + 10*1 работа с остальными=21 секунд на 11 пациентов. А если врачей больше и работают они асинхронно, то за эти 10 секунд УЗИ одного больного обслужатся 10 других пациентов=11 секунд на 11 пациентов. В этом свете накладные расходы на переключение контекста ничтожно малы.

    Джефри Рихтер об этом пишет в своей книге CLR via C#.
    В технических терминах про асинхронность можно почитать в блоге Стивена Клири.

    Если у вас в системе один контроллер и один метод в нём, вы можете выиграть от синхронного подхода если только у вас нет внутри необходимости в асинхронном получении данных и запросы приходят достаточно редко.
    Или если у вас и асинхронный контроллер, и синхронный контроллер всегда выполняют одну и ту же операцию, с одним и тем же набором данных, по одному и тому же сценарию, при одних и тех же свободных мощностях. И то это не точно.

    И на графике выше это видно.