Diferença entre #pragma omp parallel e #pragma omp parallel para
Eu sou novo OpenMP
e tenho tentado executar um programa que adiciona duas matrizes usando OpenMP. No tutorial do OpenMP, aprendi que precisamos usar #pragma omp parallel for ao usar o OpenMP no loop for . Mas eu também tentei a mesma coisa com #pragma omp parallel e também está me dando a saída correta. Abaixo estão os trechos de código do que estou tentando transmitir.
#pragma omp parallel for
{
for(int i=0;i<n;i++)
{
c[i]=a[i]+b[i];
}
}
e
#pragma omp parallel
{
for(int i=0;i<n;i++)
{
c[i]=a[i]+b[i];
}
}
Qual é a diferença entre esses dois?
Respostas
o
#pragma omp parallel
:
criará um parallel region
com uma equipe de threads
, onde cada thread executará todo o bloco de código que o parallel region
inclui.
No OpenMP 5.1 pode-se ler uma descrição mais formal:
Quando uma thread encontra uma construção paralela , uma equipe de threads é criada para executar a região paralela (..). O encadeamento que encontrou a construção paralela se torna o encadeamento principal da nova equipe, com um número de encadeamento zero para a duração da nova região paralela. Todos os threads na nova equipe, incluindo o thread principal, executam a região. Depois que a equipe é criada, o número de threads na equipe permanece constante durante a região paralela.
O:
#pragma omp parallel for
irá criar um parallel region
(como descrito antes), e para o threads
dessa região as iterações do loop que ele inclui serão atribuídas, usando o default chunk size
, e o default schedule
que é normalmente static
. Tenha em mente, entretanto, que o default schedule
pode diferir entre as diferentes implementações concretas da OpenMP
norma.
No OpenMP 5.1 você pode ler uma descrição mais formal:
A construção de loop de compartilhamento de trabalho especifica que as iterações de um ou mais loops associados serão executadas em paralelo por threads na equipe no contexto de suas tarefas implícitas. As iterações são distribuídas por threads que já existem na equipe que está executando a região paralela à qual a região do loop de compartilhamento de trabalho se liga .
Além disso ,
A construção de loop paralelo é um atalho para especificar uma construção paralela contendo uma construção de loop com um ou mais loops associados e nenhuma outra instrução.
Ou informalmente, #pragma omp parallel for
é uma combinação do construtor #pragma omp parallel
com #pragma omp for
. No seu caso, isso significaria que:
#pragma omp parallel for
{
for(int i=0;i<n;i++)
{
c[i]=a[i]+b[i];
}
}
é semanticamente e logicamente o mesmo que:
#pragma omp parallel
{
#pragma omp for
for(int i=0;i<n;i++)
{
c[i]=a[i]+b[i];
}
}
TL; DR: Em seu exemplo, com #pragma omp parallel for
o loop será paralelizado entre os threads ( ou seja, as iterações do loop serão divididas entre os threads), enquanto com #pragma omp parallel
todos os threads executará (em paralelo) todas as iterações do loop.
Para torná-lo mais ilustrativo, com 4
tópicos #pragma omp parallel
, resultaria em algo como:

enquanto que #pragma omp parallel for
com um chunk_size=1
e um estático schedule
resultaria em algo como:

Em termos de código, o loop seria transformado em algo logicamente semelhante a:
for(int i=omp_get_thread_num(); i < n; i+=omp_get_num_threads())
{
c[i]=a[i]+b[i];
}
onde omp_get_thread_num ()
A rotina omp_get_thread_num retorna o número do encadeamento, dentro da equipe atual, do encadeamento de chamada.
e omp_get_num_threads ()
Retorna o número de threads na equipe atual. Em uma seção sequencial do programa omp_get_num_threads retorna 1.
ou em outras palavras for(int i = THREAD_ID; i < n; i += TOTAL_THREADS)
,. Com THREAD_ID
variando de 0
a TOTAL_THREADS - 1
, e TOTAL_THREADS
representando o número total de threads da equipe criados na região paralela.
Aprendi que precisamos usar #pragma omp parallel for ao usar o OpenMP no loop for. Mas eu também tentei a mesma coisa com #pragma omp parallel e também está me dando a saída correta.
Ele fornece a mesma saída, porque em seu código:
c[i]=a[i]+b[i];
array a
e array b
são apenas lidos, e array c[i]
é o único que está sendo atualizado, e seu valor não depende de quantas vezes a iteração i
será executada. No entanto, com #pragma omp parallel for
cada thread será atualizado o seu próprio i
, enquanto com #pragma omp parallel
threads estará atualizando os mesmos i
s, portanto, substituindo os valores uns dos outros.
Agora tente fazer o mesmo com o seguinte código:
#pragma omp parallel for
{
for(int i=0;i<n;i++)
{
c[i]= c[i] + a[i] + b[i];
}
}
e
#pragma omp for
{
for(int i=0;i<n;i++)
{
c[i] = c[i] + a[i] + b[i];
}
}
você notará imediatamente a diferença.
No segundo caso, o loop não é paralelizado. Ou seja, todo o loop é executado em cada thread . Geralmente, tudo o que está dentro da região paralela é executado por todos os threads.
Além disso, você pode paralelizar o loop na região paralela já existente da seguinte maneira:
#pragma omp parallel
{
#pragma omp for
for (int i = 0; i < n; i++)
c[i] = a[i] + b[i];
}