Использование всех ядер на ПК с c # - PullRequest
2 голосов
/ 11 января 2012

* Обратите внимание, что я просто пытаюсь понять это.

Я пытаюсь использовать все ядра моего компьютера методом Parallel.For(). Это работает просто отлично, но когда я пытаюсь использовать тот же метод с обычным циклом for, он идет намного быстрее. Параллельный метод занимает 16 секунд, а обычный метод - только 6 секунд.

Я надеюсь, что вы можете сказать мне, что я делаю здесь неправильно.

Обновленный код

        DateTime parallelStart = new DateTime();
        DateTime parallelFinish = new DateTime();
        DateTime singeStart = new DateTime();
        DateTime singeFinish = new DateTime();
        parallelStart = DateTime.Now;
        int inputData = 0;

        Parallel.For(0, 1000000000, i =>
        {
            inputData = inputData++;
            inputData = inputData++;
            inputData = inputData++;
            inputData = inputData++;
            inputData = inputData++;
            inputData = inputData++;
            inputData = inputData++;
            inputData = inputData++;
        });

        parallelFinish = DateTime.Now;
        singeStart = DateTime.Now;

        for (int i = 0; i < 1000000000; i++)
        {
            inputData = inputData++;
            inputData = inputData++;
            inputData = inputData++;
            inputData = inputData++;
            inputData = inputData++;
            inputData = inputData++;
            inputData = inputData++;
            inputData = inputData++;
        }

        singeFinish = DateTime.Now;
        MessageBox.Show("Parallel execution time: " + (parallelFinish - parallelStart).Seconds + "\n" +
                        "Singe execution time: " + (singeFinish - singeStart).Seconds);

Первый код:

DateTime parallelStart = new DateTime();
DateTime parallelFinish = new DateTime();
DateTime singeStart = new DateTime();
DateTime singeFinish = new DateTime();
parallelStart = DateTime.Now;

Parallel.For(0, 2000000000, i =>
{
    var inputData = 0;
});

parallelFinish = DateTime.Now;
singeStart = DateTime.Now;

for (int i = 0; i < 2000000000; i++)
{
    var inputData = 0;
}

singeFinish = DateTime.Now;
MessageBox.Show("Parallel execution time: " + (parallelFinish - parallelStart).Seconds + "\n" + "Singe execution time: " + (singeFinish - singeStart).Seconds);

Ответы [ 8 ]

14 голосов
/ 11 января 2012

Ну, что быстрее: не выполняете работу самостоятельно или нанимаете по десять человек, каждый из которых выполняет по одной десятой части без работы?

Что вы делаете неправильно, так это то, что ваш пример полностью искусственный.Джиттер полностью осознает, что присвоение нуля одному и тому же локальному объекту, который не используется снова и снова, не имеет смысла, поэтому он, вероятно, исключает работу.Даже если это не так, эта работа тривиальна.Работа по настройке всех потоков больше, чем просто выполнение работы самостоятельно.

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

10 голосов
/ 11 января 2012

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

3 голосов
/ 11 января 2012

Установка значения существующего типа значения в стеке невероятно, глубоко тривиально.Стоимость создания и отслеживания потоков будет большой по сравнению с этим. Добавление любой сложности к вашей операции может кардинально изменить ваши результаты .Даже создание и установка строковой переменной, равной добавлению двух строк, значительно увеличит объем работы.Попробуйте что-то более сложное (почти все подойдет!), И вы увидите, как увеличивается значение параллельной библиотеки.

Попробуйте это:

Parallel.For(0, 2000000000, i =>
{
    var string inputData = "ninjas " + "like " + "taco";
});

Верьте или нет, мы добавили много больше обработки здесь.(В фоновом режиме создаются и отбрасываются несколько строк). Это изменит ваши результаты.И затем, если учесть, что в этих циклах мы делаем гораздо более сложные вещи, например:

  • доступ к данным
  • дисковый ввод-вывод
  • сложная математика
  • фильтрация / упорядочение / проецирование списков и т. Д.

, результаты будут впечатляющими в пользу параллелизма.

2 голосов
/ 11 января 2012

Распараллеливание кода требует довольно больших накладных расходов, и вы используете его для выполнения тривиальных операций.Вот почему ваш код работает очень медленно.Вы увидите улучшение только после того, как добавите в код свой код, и он будет выполнять много операций, интенсивно использующих процессор.

2 голосов
/ 11 января 2012

Многопоточность имеет накладные расходы.Для операций, которые занимают много времени по сравнению с затратами времени на настройку потока, отлично.

Но в вашем случае у вас очень простое тело цикла и накладные расходы на создание потоков для выполнения работы.перевешивает выгоду от параллельной работы.

1 голос
/ 11 января 2012

Как отмечается в большинстве книг по параллельному программированию, «всегда измеряйте производительность».Не думайте, что параллельное выполнение быстрее, чем использование прямого цикла, потому что параллелизм включает в себя издержки.

Вы действительно должны учитывать, сколько данных нужно обработать, уровень параллелизма и сколько необходимо обмена изменяющимися данными (сколько требуется блокировка).

0 голосов
/ 11 января 2012

Я подозреваю, без моих собственных эмпирических доказательств, что накладные расходы на добавление в очередь дополнительного потока перевешивают выгоду. То, что вы просите, - это одновременное выполнение 2 млрд. Работ, что, не проверяя, я подозреваю, что параллельные очереди с ThreadPool.

0 голосов
/ 11 января 2012

Используйте TotalSeconds вместо секунд при измерении времени.

...