Справочная информация. Обычный метод управления потоками в .NET может быть громоздким. Он хорошо работает для ограничения проблем, вызванных конфликтом ресурсов, но делает это за счет того, насколько быстро создаются потоки. Чтобы повысить производительность рабочих потоков с помощью пула потоков, разработчики предусмотрели механизм, который позволяет создавать определенное небольшое количество потоков без прохождения процесса очереди.
SetMinThreads () указывает количество потоков, которые должны быть просто созданы «по требованию», то есть просто запущены без каких-либо проверок текущего количества потоков или в очереди для медленного увеличения скорости.
Что произойдет, это то, что фреймворк сразу же создаст первые два потока, как если бы вы вручную настраивали их и запускали их с помощью Thread.Start. Кроме того, вплоть до текущего значения MaxThreads, инфраструктура начнет ставить в очередь запросы для рабочих потоков и запускать их через определенный интервал (по умолчанию 250 мс, я полагаю, это также можно настроить), чтобы избежать конфликта ресурсов. Причина этого заключается в том, что если вы представляете себе зацикленное поведение запуска потока, который обращается к ресурсу, выполняет некоторые вычисления, а затем записывает результат где-то еще, вы можете увидеть, как 5 потоков, запускающихся почти одновременно, могут вызвать переполнение, пытаясь получить на этот первый ресурс. На пороге MaxThreads очередь останавливается; новые потоки не создаются, пока не закончится.
Таким образом, по природе вашего кода будет запланировано 50 отдельных рабочих задач, но не все 50 будут выполняться одновременно; среда выполнения позволяет двум запускаться немедленно, затем подождать 250 мс или пока один не закончится, прежде чем начать следующий. Поскольку потоки будут выполняться и завершаться менее чем за 250 мс, вы вряд ли увидите более двух рабочих потоков, выполняющихся одновременно; ожидание перед созданием этого третьего никогда не произойдет, потому что «неограниченный» рабочий поток сначала освобождается, а ожидающий запускается до истечения времени ожидания, а затем часы сбрасываются со следующим.