Здесь вы столкнетесь с парой проблем.Механизм предотвращения голодания планировщика будет видеть ваши задачи заблокированными, поскольку они ожидают процессов.Ему будет трудно отличить заблокированный поток от потока, ожидающего завершения процесса.В результате он может планировать новые задачи, если ваши задачи выполняются или долго (см. Ниже).Эвристика Hillclimbing должна учитывать общую нагрузку на систему, как от вашего приложения, так и от других.Он просто пытается максимизировать выполненную работу, поэтому он будет добавлять больше работы до тех пор, пока общая пропускная способность системы не перестанет увеличиваться, а затем отключится.Я не думаю , что это повлияет на ваше приложение, но проблема избежания сохранения, вероятно, будет.
Вы можете найти более подробную информацию о том, как все это работает в Параллельное программированиес Microsoft® .NET , Колином Кэмпбеллом, Ральфом Джонсоном, Эде Миллером, Стивеном Таубом (более ранняя версия онлайн ).
"Пул потоков .NET автоматическиуправляет количеством рабочих потоков в пуле, добавляет и удаляет потоки в соответствии со встроенной эвристикой. В пуле потоков .NET есть два основных механизма для внедрения потоков: механизм предотвращения голодания, который добавляет рабочие потоки, если не видит прогрессасозданный для объектов в очереди и эвристики с ограничением по склону, которая пытается максимизировать пропускную способность при использовании как можно меньшего количества потоков.
Целью предотвращения голода является предотвращение тупиковых ситуаций. Этот вид тупиковых ситуаций может возникать, когда рабочий поток ожидаетсобытие синхронизации, которое может быть удовлетворено только рабочим элементом, который все еще ожидаетглобальные или локальные очереди пула потоков.Если бы было фиксированное количество рабочих потоков, и все эти потоки были заблокированы аналогичным образом, система не смогла бы добиться дальнейшего прогресса.Добавление нового рабочего потока решает эту проблему.
Цель эвристики с восхождением на вершину - улучшить использование ядер, когда потоки блокируются вводом-выводом или другими условиями ожидания, которые приводят к остановке процессора.По умолчанию пул управляемых потоков имеет один рабочий поток на ядро.Если один из этих рабочих потоков блокируется, существует вероятность того, что ядро будет недостаточно использовано в зависимости от общей нагрузки компьютера.Логика внедрения потока не делает различий между заблокированным потоком и потоком, выполняющим длительную и интенсивную работу процессора.Поэтому всякий раз, когда глобальные или локальные очереди пула потоков содержат ожидающие рабочие элементы, активные рабочие элементы, выполнение которых занимает много времени (более половины секунды), могут инициировать создание новых рабочих потоков пула потоков.
Пул потоков .NET имеет возможность внедрять потоки каждый раз, когда рабочий элемент завершается, или с интервалом в 500 миллисекунд, в зависимости от того, что меньше.Пул потоков использует эту возможность, чтобы попытаться добавить потоки (или убрать их), руководствуясь обратной связью с предыдущими изменениями в количестве потоков.Если добавление потоков, кажется, помогает пропускной способности, пул потоков добавляет больше;в противном случае это уменьшает количество рабочих потоков.Эту технику называют эвристической альпинизмом.Таким образом, одна из причин, по которой отдельные задачи должны быть короткими, состоит в том, чтобы избежать «обнаружения истощения», а другая причина, по которой они должны быть короткими, состоит в том, чтобы предоставить пулу потоков больше возможностей для повышения пропускной способности за счет регулировки количества потоков.Чем короче продолжительность отдельных задач, тем чаще пул потоков может измерять пропускную способность и соответствующим образом корректировать количество потоков.
Чтобы сделать это конкретным, рассмотрим крайний пример.Предположим, у вас есть сложное финансовое моделирование с 500 процессорами, интенсивно использующими процессор, каждая из которых занимает в среднем десять минут.Если вы создадите задачи верхнего уровня в глобальной очереди для каждой из этих операций, вы обнаружите, что примерно через пять минут пул потоков увеличится до 500 рабочих потоков.Причина в том, что пул потоков видит всеl задач как заблокированных и начинает добавлять новые потоки со скоростью примерно два потока в секунду.
Что не так с 500 рабочими потоками?В принципе ничего, если у вас есть 500 ядер для использования и огромное количество системной памяти.На самом деле это долгосрочное видение параллельных вычислений.Однако, если у вас не так много ядер на вашем компьютере, вы попадаете в ситуацию, когда множество потоков конкурируют за временные интервалы.Эта ситуация называется переподпиской процессора.Разрешение многим потокам, интенсивно использующим процессор, конкурировать за время на одном ядре добавляет издержки переключения контекста, которые могут серьезно снизить общую пропускную способность системы.Даже если вам не хватает памяти, производительность в этой ситуации может быть намного, намного хуже, чем при последовательных вычислениях.(Каждое переключение контекста занимает от 6000 до 8000 тактов процессора.) Стоимость переключения контекста не является единственным источником накладных расходов.Управляемый поток в .NET занимает примерно мегабайт стекового пространства, независимо от того, используется ли это пространство для выполняемых в данный момент функций.Для создания нового потока требуется около 200 000 циклов ЦП, а для удаления потока - около 100 000 циклов.Это дорогостоящие операции.
До тех пор, пока каждая задача не занимает несколько минут, алгоритм подъема пула потоков в конечном итоге обнаружит, что в нем слишком много потоков, и сам по себе сокращен.Однако, если у вас есть задачи, которые занимают рабочий поток в течение многих секунд, минут или часов, это исключит эвристику пула потоков, и в этот момент вам следует рассмотреть альтернативный вариант.
Первый вариант -Разложите ваше приложение на более короткие задачи, которые выполняются достаточно быстро, чтобы пул потоков успешно управлял количеством потоков для оптимальной пропускной способности.Вторая возможность - реализовать собственный объект планировщика задач, который не выполняет внедрение потока.Если ваши задачи имеют большую продолжительность, вам не нужен высоко оптимизированный планировщик задач, потому что стоимость планирования будет незначительной по сравнению со временем выполнения задачи.Программа разработчика MSDN® имеет пример простой реализации планировщика задач, которая ограничивает максимальную степень параллелизма.Для получения дополнительной информации см. Раздел «Дальнейшее чтение» в конце этой главы.
В качестве крайней меры вы можете использовать метод SetMaxThreads для настройки класса ThreadPool с верхним пределом для числарабочие потоки, как правило, равны количеству ядер (это свойство Environment.ProcessorCount).Этот верхний предел применяется ко всему процессу, включая все домены приложений. "