#pragma omp parallel과 #pragma omp parallel의 차이점

Dec 11 2020

나는 처음 OpenMP이고 OpenMP를 사용하여 두 개의 배열을 추가하는 프로그램을 실행하려고했습니다. OpenMP 자습서 에서 for 루프 에서 OpenMP를 사용하는 동안 #pragma omp parallel for 를 사용해야한다는 것을 배웠습니다 . 그러나 나는 또한 #pragma omp parallel으로 똑같은 것을 시도 했으며 올바른 출력을 제공합니다. 다음은 내가 전달하려는 코드 스 니펫입니다.

#pragma omp parallel for
{
      for(int i=0;i<n;i++)
       {  
            c[i]=a[i]+b[i];
       }
}

 #pragma omp parallel
{
      for(int i=0;i<n;i++)
       {  
            c[i]=a[i]+b[i];
       }
}

이 둘의 차이점은 무엇입니까?

답변

5 dreamcrash Dec 11 2020 at 15:14

그만큼

#pragma omp parallel:

parallel region의 팀으로 를 생성합니다 threads. 여기서 각 스레드는에 포함 된 전체 코드 블록을 실행합니다 parallel region.

로부터 의 OpenMP 5.1 하나 더 공식적인 설명을 읽을 수 있습니다 :

쓰레드가 만나면 평행 구조물을 , 스레드 팀 생성 병렬 영역 (..)을 실행. 병렬 구조를 만난 스레드는 새 병렬 영역의 기간 동안 스레드 번호가 0 인 새 팀의 기본 스레드가됩니다. 기본 스레드를 포함하여 새 팀의 모든 스레드가 영역을 실행합니다. 팀이 생성되면 팀의 스레드 수는 해당 병렬 영역의 기간 동안 일정하게 유지됩니다.

그만큼:

#pragma omp parallel for

를 생성한다 parallel region(앞서 설명한 바와 같이), 상기에 threads그 영역이 둘러싸는 것을 루프의 반복의 사용에 할당 될 default chunk size하고 default schedule이는 일반적 static . 그러나 표준의 default schedule구체적인 구현에 따라 다를 수 있음을 명심 하십시오 OpenMP.

로부터 의 OpenMP 5.1 당신은 더 공식적인 설명을 읽을 수 있습니다 :

작업 공유 루프 구조는 하나 이상의 연관된 루프의 반복이 암시 적 작업의 맥락에서 팀의 스레드에 의해 병렬로 실행되도록 지정합니다. 반복은 작업 공유 루프 영역이 바인딩되는 병렬 영역을 실행하는 팀에 이미 존재하는 스레드에 분산 됩니다.

또한 ,

병렬 루프 구성은 하나 이상의 연관된 루프가 있고 다른 명령문이없는 루프 구성을 포함하는 병렬 구성을 지정하기위한 단축키입니다.

또는 비공식적으로 #pragma omp parallel for생성자 #pragma omp parallel#pragma omp for. 귀하의 경우 이것은 다음을 의미합니다.

#pragma omp parallel for
{
      for(int i=0;i<n;i++)
       {  
            c[i]=a[i]+b[i];
       }
}

의미 상 논리적으로 다음과 같습니다.

#pragma omp parallel
{
      #pragma omp for
      for(int i=0;i<n;i++)
       {  
            c[i]=a[i]+b[i];
       }
}

TL; DR : 귀하의 예 #pragma omp parallel for에서 루프는 스레드간에 병렬화됩니다 ( 즉, 루프 반복은 스레드간에 분할 됨). 반면 #pragma omp parallel 모든 스레드는 모든 루프 반복 을 병렬로 실행 합니다.

더 설명하기 위해 4스레드를 사용하면 #pragma omp parallel다음과 같은 결과가 나타납니다.

반면 #pragma omp parallel fora chunk_size=1정적 schedule 은 다음과 같은 결과를 초래합니다.

코드 측면에서 루프는 논리적으로 다음 과 유사한 것으로 변환 됩니다.

for(int i=omp_get_thread_num(); i < n; i+=omp_get_num_threads())
{  
    c[i]=a[i]+b[i];
}

여기서 omp_get_thread_num ()

omp_get_thread_num 루틴은 현재 팀 내에서 호출 스레드의 스레드 번호를 리턴합니다.

및 omp_get_num_threads ()

현재 팀의 스레드 수를 반환합니다. 프로그램의 순차 섹션에서 omp_get_num_threads는 1을 반환합니다.

즉, for(int i = THREAD_ID; i < n; i += TOTAL_THREADS). 함께 THREAD_ID이르기 0까지 TOTAL_THREADS - 1, 그리고 TOTAL_THREADS병렬 영역에 생성 한 팀의 총 스레드 수를 나타내는.

for 루프에서 OpenMP를 사용하는 동안 #pragma omp parallel를 사용해야한다는 것을 배웠습니다. 그러나 나는 또한 #pragma omp parallel으로 똑같은 것을 시도했으며 올바른 출력을 제공합니다.

코드에서 다음과 같이 동일한 출력을 제공합니다.

 c[i]=a[i]+b[i];

배열 a과 배열 b은 읽기 전용이며 배열 c[i]은 업데이트되는 유일한 것이며 그 값은 반복 i이 실행되는 횟수에 의존하지 않습니다 . 그럼에도 불구하고 #pragma omp parallel for각 스레드는 자체를 업데이트하는 i반면 #pragma omp parallel스레드는 동일한을 업데이트 i하므로 서로의 값을 재정의합니다.

이제 다음 코드로 동일한 작업을 시도하십시오.

#pragma omp parallel for
{
      for(int i=0;i<n;i++)
       {  
            c[i]= c[i] + a[i] + b[i];
       }
}

#pragma omp for
{
      for(int i=0;i<n;i++)
       {  
            c[i] = c[i] + a[i] + b[i];
       }
}

그 차이를 즉시 알 수 있습니다.

2 DanielLangr Dec 11 2020 at 15:16

두 번째 경우에는 루프가 병렬화되지 않습니다. 즉, 전체 루프가 각 스레드에서 실행됩니다 . 일반적으로 병렬 영역 내부에있는 것은 모든 스레드에서 실행됩니다.

다음과 같이 기존 병렬 영역의 루프를 추가로 병렬화 할 수 있습니다.

#pragma omp parallel
{
  #pragma omp for
  for (int i = 0; i < n; i++)
    c[i] = a[i] + b[i];
}