Сколько потоков может выполняться параллельно в один момент времени
Что проверяют
Отличаете ли вы параллелизм от конкурентности и знаете ли, чем ограничен первый. Заодно смотрят, понимаете ли, что async не про потоки: именно здесь ломается большинство ответов про многопоточность в .NET.
Как отвечать
Одновременно, физически в один момент времени, выполняется столько потоков, сколько у машины логических процессоров: ядра, умноженные на число аппаратных потоков на ядро. В коде это Environment.ProcessorCount, и в современных версиях .NET он учитывает лимит CPU контейнера, а не только железо хоста.
Всё, что сверх этого числа, выполняется не параллельно, а по очереди: планировщик ОС нарезает кванты и переключает контекст. Потоков в процессе может быть тысяча, скорости это не добавит, добавит накладных расходов на переключение и памяти под стеки.
Дальше стоит перейти к пулу, потому что обычно спрашивают про него. Минимальное число потоков пула по умолчанию равно ProcessorCount, сверх минимума пул добавляет потоки медленно и по одному, проверяя, помогает ли это. Для очереди коротких задач так и надо, а для заблокированных потоков это губительно.
И главный тезис: async и await потоков не создают. Пока идёт ввод-вывод, поток не занят вообще, он возвращается в пул и берёт другую работу, поэтому тысячи одновременных запросов живут на десятке потоков. Параллелизм вычислений это Parallel.For и Task.Run, и там имеет смысл ограничивать MaxDegreeOfParallelism.
Где спотыкаются
Называют число потоков вместо числа процессоров и уверенно говорят, что тысяча потоков выполняется одновременно. Выполняется по очереди, а выигрыш съедает переключение контекста.
Блокируют потоки пула на вводе-выводе через .Result и .Wait(). Пул добирает потоки медленно, запросы копятся, задержки растут скачком, и это классическое голодание пула, которое в старых средах с контекстом синхронизации доходит до взаимной блокировки.
Заворачивают асинхронный вызов в Task.Run, чтобы «сделать его параллельным». Для чистого ввода-вывода это лишний переход в пул, а в вебе ещё и отъедает поток, который мог бы обслуживать другой запрос.