Porady: korzystanie z kontenerów równoległych do zwiększania wydajności
W tym temacie przedstawiono sposób użycia kontenerów równolegle do efektywnie przechowywania i udostępniania danych równolegle.
Przykładowy kod oblicza zestaw prime i numery Carmichael równolegle.Następnie dla każdego numeru Carmichael kod oblicza czynniki pierwsze tego numeru.
Przykład
W poniższym przykładzie pokazano is_prime funkcja, która określa, czy wartość jest liczbą pierwszą, a is_carmichael funkcja, która określa, czy wartość wejściowa jest liczbą Carmichaela.
// 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;
}
// Determines whether the input value is a Carmichael number.
bool is_carmichael(const int n)
{
if (n < 2)
return false;
int k = n;
for (int i = 2; i <= k / i; ++i)
{
if (k % i == 0)
{
if ((k / i) % i == 0)
return false;
if ((n - 1) % (i - 1) != 0)
return false;
k /= i;
i = 1;
}
}
return k != n && (n - 1) % (k - 1) == 0;
}
W poniższym przykładzie użyto is_prime i is_carmichael funkcji do obliczania zestawy prime i numery Carmichael.W przykładzie użyto concurrency::parallel_invoke i concurrency::parallel_for algorytmy obliczyć każdy zestaw równolegle.Aby uzyskać więcej informacji dotyczących algorytmów równoległych, zobacz Algorytmy równoległe.
W poniższym przykładzie użyto concurrency::concurrent_queue obiekt do przechowywania zestawu Carmichael numery, ponieważ później użyje tego obiektu jako kolejka pracy.Używa on concurrency::concurrent_vector obiekt do przechowywania zestawu liczb pierwszych, ponieważ później będzie iteracyjne przeglądanie tego zestawu, aby znaleźć czynniki pierwsze.
// The maximum number to test.
const int max = 10000000;
// Holds the Carmichael numbers that are in the range [0, max).
concurrent_queue<int> carmichaels;
// Holds the prime numbers that are in the range [0, sqrt(max)).
concurrent_vector<int> primes;
// Generate the set of Carmichael numbers and the set of prime numbers
// in parallel.
parallel_invoke(
[&] {
parallel_for(0, max, [&](int i) {
if (is_carmichael(i)) {
carmichaels.push(i);
}
});
},
[&] {
parallel_for(0, int(sqrt(static_cast<double>(max))), [&](int i) {
if (is_prime(i)) {
primes.push_back(i);
}
});
});
W poniższym przykładzie pokazano prime_factors_of funkcja, która korzysta z wersji próbnej rejon do znalezienia wszystkich głównych czynników o podaną wartość.
Ta funkcja wykorzystuje concurrency::parallel_for_each algorytm umożliwia iteracyjne przeglądanie zbioru liczb pierwszych.concurrent_vector Obiektu umożliwia równoległe pętli jednocześnie dodać czynniki pierwsze do wyniku.
// Finds all prime factors of the given value.
concurrent_vector<int> prime_factors_of(int n,
const concurrent_vector<int>& primes)
{
// Holds the prime factors of n.
concurrent_vector<int> prime_factors;
// Use trial division to find the prime factors of n.
// Every prime number that divides evenly into n is a prime factor of n.
const int max = sqrt(static_cast<double>(n));
parallel_for_each(begin(primes), end(primes), [&](int prime)
{
if (prime <= max)
{
if ((n % prime) == 0)
prime_factors.push_back(prime);
}
});
return prime_factors;
}
W tym przykładzie przetwarza każdy element w kolejce numery Carmichael przez wywołanie prime_factors_of funkcji do obliczania jego czynniki pierwsze.Grupa zadań używa do wykonywania tej pracy równolegle.Aby uzyskać więcej informacji dotyczących grup zadań, zobacz Równoległość zadania (współbieżność środowiska wykonawczego).
W tym przykładzie drukuje czynniki pierwsze dla każdego numeru Carmichael, jeśli ten numer ma więcej niż cztery główne czynniki.
// Use a task group to compute the prime factors of each
// Carmichael number in parallel.
task_group tasks;
int carmichael;
while (carmichaels.try_pop(carmichael))
{
tasks.run([carmichael,&primes]
{
// Compute the prime factors.
auto prime_factors = prime_factors_of(carmichael, primes);
// For brevity, print the prime factors for the current number only
// if there are more than 4.
if (prime_factors.size() > 4)
{
// Sort and then print the prime factors.
sort(begin(prime_factors), end(prime_factors));
wstringstream ss;
ss << L"Prime factors of " << carmichael << L" are:";
for_each (begin(prime_factors), end(prime_factors),
[&](int prime_factor) { ss << L' ' << prime_factor; });
ss << L'.' << endl;
wcout << ss.str();
}
});
}
// Wait for the task group to finish.
tasks.wait();
Poniższy kod przedstawia przykład pełną, który użyto równoległych pojemników do obliczenia na czynniki pierwsze numery Carmichael.
// carmichael-primes.cpp
// compile with: /EHsc
#include <ppl.h>
#include <concurrent_queue.h>
#include <concurrent_vector.h>
#include <iostream>
#include <sstream>
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;
}
// Determines whether the input value is a Carmichael number.
bool is_carmichael(const int n)
{
if (n < 2)
return false;
int k = n;
for (int i = 2; i <= k / i; ++i)
{
if (k % i == 0)
{
if ((k / i) % i == 0)
return false;
if ((n - 1) % (i - 1) != 0)
return false;
k /= i;
i = 1;
}
}
return k != n && (n - 1) % (k - 1) == 0;
}
// Finds all prime factors of the given value.
concurrent_vector<int> prime_factors_of(int n,
const concurrent_vector<int>& primes)
{
// Holds the prime factors of n.
concurrent_vector<int> prime_factors;
// Use trial division to find the prime factors of n.
// Every prime number that divides evenly into n is a prime factor of n.
const int max = sqrt(static_cast<double>(n));
parallel_for_each(begin(primes), end(primes), [&](int prime)
{
if (prime <= max)
{
if ((n % prime) == 0)
prime_factors.push_back(prime);
}
});
return prime_factors;
}
int wmain()
{
// The maximum number to test.
const int max = 10000000;
// Holds the Carmichael numbers that are in the range [0, max).
concurrent_queue<int> carmichaels;
// Holds the prime numbers that are in the range [0, sqrt(max)).
concurrent_vector<int> primes;
// Generate the set of Carmichael numbers and the set of prime numbers
// in parallel.
parallel_invoke(
[&] {
parallel_for(0, max, [&](int i) {
if (is_carmichael(i)) {
carmichaels.push(i);
}
});
},
[&] {
parallel_for(0, int(sqrt(static_cast<double>(max))), [&](int i) {
if (is_prime(i)) {
primes.push_back(i);
}
});
});
// Use a task group to compute the prime factors of each
// Carmichael number in parallel.
task_group tasks;
int carmichael;
while (carmichaels.try_pop(carmichael))
{
tasks.run([carmichael,&primes]
{
// Compute the prime factors.
auto prime_factors = prime_factors_of(carmichael, primes);
// For brevity, print the prime factors for the current number only
// if there are more than 4.
if (prime_factors.size() > 4)
{
// Sort and then print the prime factors.
sort(begin(prime_factors), end(prime_factors));
wstringstream ss;
ss << L"Prime factors of " << carmichael << L" are:";
for_each (begin(prime_factors), end(prime_factors),
[&](int prime_factor) { ss << L' ' << prime_factor; });
ss << L'.' << endl;
wcout << ss.str();
}
});
}
// Wait for the task group to finish.
tasks.wait();
}
Ten przykład generuje następujące przykładowe wyniki.
Kompilowanie kodu
Skopiuj przykładowy kod i wklej go w projekcie programu Visual Studio lub wkleić go w pliku o nazwie carmichael primes.cpp , a następnie uruchomić następujące polecenie w oknie wiersza polecenia programu Visual Studio.
cl.exe /EHsc carmichael-primes.cpp
Zobacz też
Informacje
Koncepcje
Równoległe kontenery oraz obiekty
Równoległość zadania (współbieżność środowiska wykonawczego)