Странное время выполнения в версиях Debug и Release - PullRequest
1 голос
/ 03 марта 2012

Я начал играть с Parallel Pattern Library в VS2010, приложение дает мне ожидаемые результаты, но когда я сравниваю отладочную версию и версию выпуска, я получаю странное время выполнения в версии выпуска, как показано ниже. Отладочная версия: "Последовательная продолжительность: 1014" "ПараллельПродолжительность: 437 "Выпускная версия" Последовательная продолжительность: 31 "" Параллельная продолжительность: 484 "

Это код моего приложения

double DoWork(int workload)
{
    double result=0;
    for(int i =0 ; i < workload;i++)
    {
        result +=sqrt((double)i * 4*3) + i* i;
    }
    return result;
}

vector<double> Seqential()
{
    vector<double> results(100);
    for(int i = 0 ; i <100 ; i++)
    {
        results[i] = DoWork(1000000);
    }

    return results;
}

vector<double> Parallel()
{
     vector<double> results(100);
     parallel_for(0,(int)100,1,[&results](int i)
     {
         results[i] = DoWork(1000000);
     });

     return results;
}

double Sum(const vector<double>& results)
{
    double result =0;
    for(int i = 0 ; i < results.size();i++)
        result += results[i];
    return result;
}

int main()
{
    DWORD start = GetTickCount();
    vector<double> results = Seqential();
    DWORD duration = GetTickCount() - start;
    cout<<"Sequential Duration : "<<duration <<"  Result : " <<Sum(results) << endl;

    start = GetTickCount();
    results = Parallel();
    duration = GetTickCount() - start;
    cout<<"Prallel Duration : "<<duration <<"  Result : " <<Sum(results) << endl;
    system("PAUSE");
    return 0;
}

Ответы [ 3 ]

2 голосов
/ 03 марта 2012

IIRC, C ++ 11 позволяет компилятору углубиться в функции для предварительного вычисления константных выражений во время компиляции, даже такие функции, как sqrt.Таким образом, ваша последовательная версия может быть оптимизирована вплоть до таблицы результатов.Возможно, вы захотите посмотреть на сгенерированную сборку для Sequential, если это возможно, и посмотреть, не выглядит ли она слишком упрощенной или, возможно, полностью оптимизированной.

В DoWork нет ничего, что не может быть вычислено во время компиляции.

1 голос
/ 03 марта 2012

Проблема не в медленном Parallel, а в Seqential, слишком быстром:

  • В Seqential компилятор видит, что DoWork всегда будет давать один и тот же результат, поэтому цикл, вызывающий его 100 раз, оптимизируется, и DoWork в конечном итоге вызывается только один раз .
  • Компилятор не достаточно умен, чтобы оптимизировать parallel_for таким же образом, поэтому он в конечном итоге выполняет реальную работу (на самом деле в 100 раз больше фактической работы).

Если вы сделаете DoWork зависимым от счетчика цикла, различные вызовы теперь будут давать разные результаты, поэтому никакие вызовы не будут избыточными, поэтому компилятору будет нечего оптимизировать.

Например:

#include <vector>
#include <iostream>
#include <math.h>
#include <ppl.h>
#include <Windows.h>

using namespace std;
using namespace Concurrency;

double DoWork(int workload, int outer_i)
{
double result=0;
for(int i =0 ; i < workload;i++)
{
    result +=sqrt((double)i * 4*3) + i* i;
}
result += outer_i;
return result;
}

vector<double> Seqential()
{
vector<double> results(100);
for(int i = 0 ; i <100 ; i++)
{
    results[i] = DoWork(1000000, i);
}

return results;
}

vector<double> Parallel()
{
vector<double> results(100);
parallel_for(0,(int)100,1,[&results](int i)
{
    results[i] = DoWork(1000000, i);
});

return results;
}

double Sum(const vector<double>& results)
{
double result =0;
for(int i = 0 ; i < results.size();i++)
    result += results[i];
return result;
}

int main()
{
DWORD start = GetTickCount();
vector<double> results = Seqential();
DWORD duration = GetTickCount() - start;
cout<<"Sequential Duration : "<<duration <<"  Result : " <<Sum(results) << endl;

start = GetTickCount();
results = Parallel();
duration = GetTickCount() - start;
cout<<"Prallel Duration : "<<duration <<"  Result : " <<Sum(results) << endl;
system("PAUSE");
return 0;
}

При сборке Visual C ++ 2010 в конфигурации выпуска и запуске на четырехъядерном процессоре это выдает:

Sequential Duration : 1607  Result : 1.68692e+015
Prallel Duration : 374  Result : 1.68692e+015

(Кстати, вам действительно следует лучше отформатировать код.)

1 голос
/ 03 марта 2012

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

Если вы заставите DoWork выполнять гораздо больше работы (например, многократно повторяя циклы), вы увидите результаты, более точно соответствующие вашим ожиданиям.

...