1

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;
}
4

3 に答える 3

2

IIRC、C ++ 11を使用すると、コンパイラーは関数をかなり深く掘り下げて、コンパイル時に定数式を事前に計算できますsqrt。したがって、シーケンシャルバージョンは、結果のテーブルに至るまで最適化されている可能性があります。可能であれば、Sequential用に生成されたアセンブリを調べて、過度に単純化されているか、完全に最適化されているかどうかを確認することをお勧めします。

DoWorkコンパイル時に計算できないことについては何もありません。

于 2012-03-03T05:04:51.647 に答える
1

問題はParallel遅いことではなく、速すぎることSeqentialです。

  • ではSeqential、コンパイラはDoWorkが常に同じ結果を生成することを認識しているため、これを 100 回呼び出すループは最適化されなくなり、最終的には 1 回だけ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 によってビルドされ、クアッドコア CPU で実行されると、次のように出力されます。

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

(ところで、コードをより適切にフォーマットすることを本当に検討する必要があります。)

于 2012-03-03T15:04:45.277 に答える
1

発生している可能性があるのは、単に結果を計算するよりも、複数のスレッドを生成するオーバーヘッドの方が時間がかかっていることです。リリース ビルドでは、コンパイラは多くの最適化を行うことができるため、内部で行われる作業DoWorkの量は、スレッドをセットアップして破棄するために必要な作業の量と比較してかなり少なくなります。

より多くの作業 (ループを何度も実行するDoWorkなど) を行うと、期待に近い結果が得られます。

于 2012-03-03T05:01:27.123 に答える