Porady: konwertowanie paraleli OpenMP dla pętli do korzystania ze współbieżności środowiska wykonawczego
W tym przykładzie pokazano, jak przekonwertować pętlę podstawową, która używa równoległych protokołu OpenMP i dla dyrektyw, aby używać współbieżności środowiska uruchomieniowego współbieżności::p arallel_for algorithm.
Przykład — liczba pierwszych
W tym przykładzie użyto zarówno protokołu OpenMP, jak i środowiska uruchomieniowego współbieżności, aby obliczyć liczbę liczb pierwszych w tablicy wartości losowych.
// concrt-omp-count-primes.cpp
// compile with: /EHsc /openmp
#include <ppl.h>
#include <random>
#include <array>
#include <iostream>
using namespace concurrency;
using namespace std;
// Determines whether the input value is prime.
bool is_prime(int n)
{
if (n < 2)
return false;
for (int i = 2; i < n; ++i)
{
if ((n % i) == 0)
return false;
}
return true;
}
// Uses OpenMP to compute the count of prime numbers in an array.
void omp_count_primes(int* a, size_t size)
{
if (size == 0)
return;
size_t count = 0;
#pragma omp parallel for
for (int i = 0; i < static_cast<int>(size); ++i)
{
if (is_prime(a[i])) {
#pragma omp atomic
++count;
}
}
wcout << L"found " << count
<< L" prime numbers." << endl;
}
// Uses the Concurrency Runtime to compute the count of prime numbers in an array.
void concrt_count_primes(int* a, size_t size)
{
if (size == 0)
return;
combinable<size_t> counts;
parallel_for<size_t>(0, size, [&](size_t i)
{
if (is_prime(a[i])) {
counts.local()++;
}
});
wcout << L"found " << counts.combine(plus<size_t>())
<< L" prime numbers." << endl;
}
int wmain()
{
// The length of the array.
const size_t size = 1000000;
// Create an array and initialize it with random values.
int* a = new int[size];
mt19937 gen(42);
for (size_t i = 0; i < size; ++i) {
a[i] = gen();
}
// Count prime numbers by using OpenMP and the Concurrency Runtime.
wcout << L"Using OpenMP..." << endl;
omp_count_primes(a, size);
wcout << L"Using the Concurrency Runtime..." << endl;
concrt_count_primes(a, size);
delete[] a;
}
W tym przykładzie są generowane następujące dane wyjściowe.
Using OpenMP...
found 107254 prime numbers.
Using the Concurrency Runtime...
found 107254 prime numbers.
Algorytm parallel_for
i openMP 3.0 umożliwiają typ indeksu jako typ całkowitoliczbowy ze znakiem lub niepodpisany typ całkowity. Algorytm parallel_for
zapewnia również, że określony zakres nie przepełnia typu podpisanego. Protokół OpenMP w wersjach 2.0 i 2.5 zezwala tylko na podpisane typy indeksów całkowitych. Protokół OpenMP również nie weryfikuje zakresu indeksów.
Wersja tego przykładu korzystająca ze środowiska uruchomieniowego współbieżności używa również obiektu współbieżności::łączenie obiektu zamiast dyrektywy niepodzielnej w celu zwiększenia wartości licznika bez konieczności synchronizacji.
Aby uzyskać więcej informacji na temat parallel_for
i innych algorytmów równoległych, zobacz Parallel Algorithms (Algorytmy równoległe). Aby uzyskać więcej informacji na temat combinable
klasy, zobacz Parallel Containers and Objects (Kontenery równoległe i obiekty).
Przykład — użyj polecenia std::array
W tym przykładzie zmodyfikowano poprzedni obiekt, aby działał na obiekcie std::array zamiast na macierzy natywnej. Ponieważ wersje OpenMP 2.0 i 2.5 umożliwiają używanie tylko podpisanych typów indeksów całkowitych w parallel_for
konstrukcji, nie można używać iteratorów do uzyskiwania dostępu do elementów kontenera biblioteki standardowej języka C++ równolegle. Biblioteka wzorców równoległych (PPL) udostępnia współbieżność::p arallel_for_each algorytmu, który wykonuje zadania równolegle w kontenerze iteracyjnym, takim jak te dostarczane przez bibliotekę standardową języka C++. Używa tej samej logiki partycjonowania, która jest używana przez parallel_for
algorytm. Algorytm parallel_for_each
przypomina algorytm std::for_each biblioteki standardowej języka C++, z tą różnicą, że parallel_for_each
algorytm wykonuje zadania współbieżnie.
// Uses OpenMP to compute the count of prime numbers in an
// array object.
template<size_t Size>
void omp_count_primes(const array<int, Size>& a)
{
if (a.size() == 0)
return;
size_t count = 0;
int size = static_cast<int>(a.size());
#pragma omp parallel for
for (int i = 0; i < size; ++i)
{
if (is_prime(a[i])) {
#pragma omp atomic
++count;
}
}
wcout << L"found " << count
<< L" prime numbers." << endl;
}
// Uses the Concurrency Runtime to compute the count of prime numbers in an
// array object.
template<size_t Size>
void concrt_count_primes(const array<int, Size>& a)
{
if (a.size() == 0)
return;
combinable<size_t> counts;
parallel_for_each(begin(a), end(a), [&counts](int n)
{
if (is_prime(n)) {
counts.local()++;
}
});
wcout << L"found " << counts.combine(plus<size_t>())
<< L" prime numbers." << endl;
}
Kompilowanie kodu
Skopiuj przykładowy kod i wklej go w projekcie programu Visual Studio lub wklej go w pliku o nazwie concrt-omp-count-primes.cpp
, a następnie uruchom następujące polecenie w oknie wiersza polecenia programu Visual Studio.
cl.exe /EHsc /openmp concrt-omp-count-primes.cpp
Zobacz też
Migrowanie z OpenMP do środowiska uruchomieniowego współbieżności
Algorytmy równoległe
Równoległe kontenery oraz obiekty