0

VC++、ネストされたループの OpenMP 並列処理をテストしますが、奇妙な結果が得られます。

  • パフォーマンスの向上なし
  • 大きなループの場合、SUM 計算は間違っています。入れ子になったループが 5 つしかない場合は、問題ありません。

結果は次のとおりです。

Sum=450000000000.000000 Serial time:        117376.852855
Sum=228067994200.000000 Parallel time:      117391.867931

作業コードは次のとおりです。

#include "stdafx.h"
#include <omp.h>
#include <ppl.h>

double Serial(), Parallel();

int _tmain(int argc, _TCHAR* argv[])
{
printf("Sum=%f Serial time:        %lf\n",Serial(),omp_get_wtime() );
printf("Sum=%f Parallel time:      %lf\n",Parallel(),omp_get_wtime() );

return 0;
}

double Serial()
{
double sum=0.;
int n=10;

for (int i01=0; i01<n; i01++){
for (int i02=0; i02<n; i02++){
for (int i03=0; i03<n; i03++){
for (int i04=0; i04<n; i04++){
for (int i05=0; i05<n; i05++){
for (int i06=0; i06<n; i06++){
for (int i07=0; i07<n; i07++){
for (int i08=0; i08<n; i08++){
for (int i09=0; i09<n; i09++){
for (int i10=0; i10<n; i10++){

sum+=i01+i02+i03+i04+i05+i06+i07+i08+i09+i10;

}}}}} }}}}}
return sum;
}

double Parallel()
{
double sum=0.;

#pragma omp parallel for shared(sum)
for (int i01=0; i01<10; i01++){
for (int i02=0; i02<10; i02++){
for (int i03=0; i03<10; i03++){
for (int i04=0; i04<10; i04++){
for (int i05=0; i05<10; i05++){
for (int i06=0; i06<10; i06++){
for (int i07=0; i07<10; i07++){
for (int i08=0; i08<10; i08++){
for (int i09=0; i09<10; i09++){
for (int i10=0; i10<10; i10++){

sum+=i01+i02+i03+i04+i05+i06+i07+i08+i09+i10;

}}}}} }}}}}
return sum;
}
4

1 に答える 1

0

共有する必要があると正しく推測しましたが、実際にはこれは削減変数であり、代わりに節にsum入れる必要があります。reduction

#pragma omp parallel for reduction(+:sum)

別のオプション (遅い) は、インクリメントをアトミックにすることです。この場合、アトミック操作はやり過ぎになりますが、単純なリダクションが適用できない、より複雑なケースで役立ちます。たとえば、配列をリダクションする場合などです。

#pragma omp atomic update
sum+=i01+i02+i03+i04+i05+i06+i07+i08+i09+i10;

このupdate句は、OpenMP 3.1 に由来します。Visual Studio は 2.0 しかサポートしていないため、理解できませんが、いつの日か、より優れたコンパイラに移行したいと思うかもしれません。

于 2013-01-29T22:42:35.890 に答える