Можно ли изменить parallelOptions.MaxDegreeOfParallelism во время выполнения Parallel.ForEach

Я запускаю многопоточный цикл:

protected ParallelOptions parallelOptions = new ParallelOptions();

parallelOptions.MaxDegreeOfParallelism = 2;
Parallel.ForEach(items, parallelOptions, item =>
{
// Loop code here
});

Я хочу изменить parallelOptions.MaxDegreeOfParallelism во время выполнения параллельного цикла, чтобы уменьшить или увеличить количество потоков.

parallelOptions.MaxDegreeOfParallelism = 5;

Кажется, что потоки не увеличиваются. У кого-нибудь есть идеи?


person John Egbert    schedule 13.09.2010    source источник
comment
Можете ли вы объяснить, почему вы хотите это сделать? Он уже сам увеличит количество потоков до указанного максимума, если это необходимо, или будет использовать меньше, если это уместно.   -  person Ian Mercer    schedule 14.09.2010
comment
В основном для управления приложением, когда оно использует слишком много ресурсов на общем сервере. Я заставляю сервер работать на 100%, что снижает скорость отклика других приложений на серверах.   -  person John Egbert    schedule 14.09.2010
comment
Это проблема с процессором или другими «ресурсами», такими как диск?   -  person Ian Mercer    schedule 14.09.2010
comment
Этот случай, в частности, относится к процессору, но количество потоков может влиять на память и диск, а также в зависимости от содержимого foreach. Я хотел бы иметь возможность изменить общее количество используемых потоков, если системные ресурсы становятся слишком большими.   -  person John Egbert    schedule 14.09.2010
comment
См. также stackoverflow.com/questions/3488381/   -  person Ian Mercer    schedule 14.09.2010


Ответы (2)


Проблема даже с попыткой сделать это заключается в том, что это трудная проблема. Во-первых, как вы вообще надежно отслеживаете загрузку ЦП и диска? Нечастая выборка ЦП даст плохую картину того, что на самом деле происходит, а выборка использования диска еще сложнее. Во-вторых, какова степень детализации ваших задач и как часто вы можете быстро менять количество выполняемых задач. В-третьих, вещи быстро меняются со временем, поэтому вам нужно применить какую-то фильтрацию к вашим наблюдениям. В-четвертых, идеальное количество потоков будет зависеть от процессора, на котором фактически выполняется код. В-пятых, если вы выделите слишком много потоков, вы будете метаться между ними вместо того, чтобы выполнять полезную работу.

См. http://msdn.microsoft.com/en-us/magazine/ff960958.aspx для обсуждения того, как пул потоков в .NET справляется со сложной задачей определения количества используемых потоков.

Вы также можете использовать рефлектор и взглянуть на код, который TPL использует для распределения потоков и предотвращения ненужного переключения контекста — он сложный и даже не принимает во внимание доступ к диску!

Вместо этого вы можете попробовать выполнить задачи в потоке с более низким приоритетом (создание собственного TaskScheduler, который запускает потоки с приоритетом ниже нормального, на самом деле довольно просто). По крайней мере, это гарантирует, что вы сможете запустить ЦП на 100%, не влияя на остальную часть системы. Игра с приоритетами потоков сама по себе чревата проблемами, но если это чисто фоновая задача, это может быть просто и может помочь.

Часто, однако, использование диска является настоящим виновником, когда дело доходит до других приложений, страдающих от рук одного жадного приложения. Windows может легко распределять ЦП между приложениями, но когда речь идет о относительно медленном доступе к диску, это совсем другое дело. Вместо того, чтобы пытаться динамически регулировать количество запущенных потоков, вам может потребоваться просто ограничить ваше приложение, чтобы оно не слишком часто обращалось к диску. Это то, что вы можете сделать, не меняя количество активных потоков.

Вы также можете рассматривать SetPriorityClass как способ сообщить ОС, что ваш процесс менее важен, чем другие приложения, работающие в системе, см. Как можно увеличить приоритет ввода/вывода процесса? для получения дополнительной информации. Но это предполагает, что весь ваш процесс менее важен, а не только эта его часть.

person Ian Mercer    schedule 14.09.2010

Я бы не ожидал, что можно будет изменить степень параллелизма после того, как вы вызвали ForEach. Насколько я понимаю, ForEach будет определять, сколько потоков он может создать, создать такое количество разделов и создать потоки для работы с этими разделами. Нет момента, когда он может сказать: «О, подождите, он изменил наше распределение ресурсов, позвольте мне переразбить массив и перераспределить потоки».

person Jim Mischel    schedule 13.09.2010
comment
Да, конечно, я согласен с вашим пониманием, но не могли бы вы добавить ссылку? - person Abdul Saboor; 16.04.2013