Почему Parallel.ForEach не запускает несколько потоков?
Сегодня я попытался сделать некоторую оптимизацию для оператора foreach
, который работает на XDocument
.
Перед оптимизацией:
foreach (XElement elem in xDoc.Descendants("APSEvent").ToList())
{
//some operations
}
После оптимизации:
Parallel.ForEach(xDoc.Descendants("APSEvent").ToList(), elem =>
{
//same operations
});
Я увидел, что .NET в Parallel.ForEach(...)
открыт ТОЛЬКО один поток! В результате временной интервал Parallel
был больше стандартного foreach
.
Почему вы думаете, что .NET только открыл 1 поток? Из-за блокировки файла?
Благодаря
Ответы
Ответ 1
По дизайну Parallel.ForEach может использовать меньшее количество потоков, чем требуется для достижения более высокой производительности. Согласно MSDN [link]:
По умолчанию методы Parallel.ForEach и Parallel.For могут использовать переменное количество задач. Вот почему, например, класс ParallelOptions обладает свойством MaxDegreeOfParallelism вместо свойства MinDegreeOfParallelism. Идея состоит в том, что система может использовать меньше потоков, чем запросить обработку цикла.
Пул потоков .NET динамически адаптируется к изменяющимся рабочим нагрузкам, позволяя с течением времени изменять количество рабочих потоков для параллельных задач. Во время выполнения система наблюдает, увеличивается ли увеличение количества потоков или ухудшает общую пропускную способность и соответственно корректирует количество рабочих потоков.
Ответ 2
используйте его следующим образом:
int ParallelThreads = 10;
Parallel.ForEach(xDoc.Descendants("APSEvent").ToList(), new ParallelOptions() { MaxDegreeOfParallelism = ParallelThreads }, (myXDOC, i, j) =>
{
//do whatever you want here
});
Ответ 3
Из описания проблемы ничего не объясняется, почему TPL не порождает больше потоков.
В вопросе нет никаких доказательств, что даже проблема. Это можно устранить довольно легко: вы можете записать идентификатор потока, прежде чем вводить цикл, и как первая вещь, которую вы делаете внутри своего цикла.
Если это всегда одно и то же число, то TPL не сможет генерировать потоки. Затем вы должны попробовать разные версии вашего кода и какое изменение запускает TPL для сериализации всего. Одна из причин может быть, если в вашем списке небольшое количество элементов. TPL разделяет вашу коллекцию, и если у вас есть только несколько элементов, вы можете получить только одну партию. Это поведение настраивается, кстати.
Возможно, вы случайно включили блокировку в цикле, тогда вы увидите множество разных чисел, но не ускорьтесь. Затем упростите код, пока проблема не исчезнет.
Ответ 4
Не всегда параллельный путь быстрее, чем "старый способ",
http://social.msdn.microsoft.com/Forums/en-US/parallelextensions/thread/c860cf3f-f7a6-46b5-8a07-ca2f413258dd
Ответ 5
Да точно, Document.Load(...)
блокирует файл и из-за конфликта ресурсов между потоками, TPL не может использовать мощность нескольких потоков. Попробуйте загрузить XML в Stream
, а затем используйте Parallel.For(...)
.
Ответ 6
Есть ли у вас один процессор? В этом случае TPL может ограничить количество потоков. То же самое может произойти, если коллекция очень мала. Попробуйте большую коллекцию.
Подробнее о том, как определяется степень parallelism, см. этот ответ.