HOW TO:使用平行容器提高效率
本主題將示範如何使用平行容器,以平行方式有效率地儲存和存取資料。
此範例程式碼會以平行方式計算質數和 Carmichael 數字的集合。 然後,此程式碼會針對每個 Carmichael 數字,計算該數字的質因數。
範例
下列範例顯示了 is_prime 函式 (它會判斷輸入值是否為質數) 以及 is_carmichael 函式 (它會判斷輸入值是否為 Carmichael 數字)。
// 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;
}
下列範例會使用 is_prime 和 is_carmichael 函式來計算質數和 Carmichael 數字的集合。 此範例會使用 Concurrency::parallel_invoke 和 Concurrency::parallel_for 演算法,以平行方式計算每個集合。 如需平行演算法的詳細資訊,請參閱平行演算法。
這個範例會使用 Concurrency::concurrent_queue 物件來保存 Carmichael 數字的集合,因為它之後將使用該物件當做工作佇列。 它會使用 Concurrency::concurrent_vector 物件來保存質數的集合,因為它之後將逐一查看此集合來尋找質因數。
// 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);
}
});
});
下列範例顯示了 prime_factors_of 函式,它會使用試除法來尋找給定值的所有質因數。
此函式會使用 Concurrency::parallel_for_each 演算法來逐一查看質數的集合。 concurrent_vector 物件可讓平行迴圈以並行方式將質因數加入至結果。
// 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(primes.begin(), primes.end(), [&](int prime)
{
if (prime <= max)
{
if ((n % prime) == 0)
prime_factors.push_back(prime);
}
});
return prime_factors;
}
這個範例會透過呼叫 prime_factors_of 函式來計算質因數,處理 Carmichael 數字佇列中的每個項目。 它會使用工作群組,以平行方式執行這項工作。 如需工作群組的詳細資訊,請參閱工作平行處理原則 (並行執行階段)。
這個範例會列印每個 Carmichael 數字的質因數 (如果該數字的質因數超過四個的話)。
// 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(prime_factors.begin(), prime_factors.end());
wstringstream ss;
ss << L"Prime factors of " << carmichael << L" are:";
for_each (prime_factors.begin(), prime_factors.end(),
[&](int prime_factor) { ss << L' ' << prime_factor; });
ss << L'.' << endl;
wcout << ss.str();
}
});
}
// Wait for the task group to finish.
tasks.wait();
下列程式碼顯示了完整的範例,其中使用平行容器來計算 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(primes.begin(), primes.end(), [&](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(prime_factors.begin(), prime_factors.end());
wstringstream ss;
ss << L"Prime factors of " << carmichael << L" are:";
for_each (prime_factors.begin(), prime_factors.end(),
[&](int prime_factor) { ss << L' ' << prime_factor; });
ss << L'.' << endl;
wcout << ss.str();
}
});
}
// Wait for the task group to finish.
tasks.wait();
}
這個範例 (Example) 產生下列範例 (Sample) 輸出。
Prime factors of 9890881 are: 7 11 13 41 241.
Prime factors of 825265 are: 5 7 17 19 73.
Prime factors of 1050985 are: 5 13 19 23 37.
編譯程式碼
請複製範例程式碼,並將它貼在 Visual Studio 專案中,或貼在名為 carmichael-primes.cpp 的檔案中,然後在 Visual Studio 2010 的 [命令提示字元] 視窗中執行下列命令。
cl.exe /EHsc carmichael-primes.cpp