C # параллельный foreach не дает ожидаемого ускорения - PullRequest
0 голосов
/ 24 октября 2018

Я пытаюсь выяснить, почему параллельный foreach не дает ожидаемого ускорения на машине с 32 физическими ядрами и 64 логическими ядрами с помощью простого тестового вычисления.

... 
var parameters = new List<string>();
for (int i = 1; i <= 9; i++) {
    parameters.Add(i.ToString());
    if (Scenario.UsesParallelForEach)
    {
        Parallel.ForEach(parameters, parameter => {
            FireOnParameterComputed(this, parameter, Thread.CurrentThread.ManagedThreadId, "started");
            var lc = new LongComputation();
            lc.Compute();
            FireOnParameterComputed(this, parameter, Thread.CurrentThread.ManagedThreadId, "stopped");
        });
    } 
    else
    {
        foreach (var parameter in parameters)
        {
            FireOnParameterComputed(this, parameter, Thread.CurrentThread.ManagedThreadId, "started");
            var lc = new LongComputation();
            lc.Compute();
            FireOnParameterComputed(this, parameter, Thread.CurrentThread.ManagedThreadId, "stopped");
        }
    }
}
...

class LongComputation
{
    public void Compute()
    {
        var s = "";
        for (int i = 0; i <= 40000; i++)
        {
            s = s + i.ToString() + "\n";
        }
    }
}

Функция Compute занимает около 5секунд до завершения.Я предполагал, что в параллельном цикле foreach каждая дополнительная итерация создает параллельный поток, работающий на одном из ядер и требующий столько же, сколько требуется для вычисления функции Compute только один раз.Итак, если я запускаю цикл дважды, то с последовательным foreach это займет 10 секунд, а с параллельным foreach всего 5 секунд (при условии, что доступно 2 ядра).Ускорение составило бы 2. Если я запускаю цикл три раза, то с последовательным foreach это займет 15 секунд, но снова с параллельным foreach всего 5 секунд.Ускорение будет 3, затем 4, 5, 6, 7, 8 и 9. Однако, что я наблюдаю, это постоянное ускорение 1,3.

Последовательный и параллельный foreach.Ось X: номер последовательного / параллельного выполнения вычисления.Ось Y: время в секундах

Ускорение, время последовательного foreach, деленное на параллельный foreach

Событие, инициируемое в FireOnParameterComputed, предназначено для использования виндикатор выполнения GUI, чтобы показать прогресс.На индикаторе выполнения четко видно, что для каждой итерации создается новый поток.

Мой вопрос: почему я не вижу ожидаемое ускорение или, по крайней мере, близко к ожидаемому ускорению?

1 Ответ

0 голосов
/ 24 октября 2018

Задачи не являются потоками.

Иногда запуск задачи вызывает создание потока, но не всегда.Создание и управление потоками требует времени и системных ресурсов.Когда задача занимает короткое время, даже если она не интуитивна, однопоточная модель часто быстрее.

CLR знает об этом и пытается высказать свое лучшее мнение о том, как выполнить задачуна основе ряда факторов, включая любые подсказки, которые вы ему передали.

Для Parallel.ForEach, если вы уверены, что хотите, чтобы несколько потоков создавались, попробуйте передать в ParallelOptions.

Parallel.ForEach(parameters, new ParallelOptions { MaxDegreeOfParallelism = 100 }, parameter => {});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...