HOW TO:撰寫 parallel_for 迴圈
本範例將示範如何使用 concurrency::parallel_for 來計算兩個矩陣的乘積。
範例
下列範例顯示了 matrix_multiply 函式,它會計算兩個平方矩陣的乘積。
// Computes the product of two square matrices.
void matrix_multiply(double** m1, double** m2, double** result, size_t size)
{
for (size_t i = 0; i < size; i++)
{
for (size_t j = 0; j < size; j++)
{
double temp = 0;
for (int k = 0; k < size; k++)
{
temp += m1[i][k] * m2[k][j];
}
result[i][j] = temp;
}
}
}
下列範例顯示了 parallel_matrix_multiply 函式,它會使用 parallel_for 演算法,以平行方式執行外部迴圈。
// Computes the product of two square matrices in parallel.
void parallel_matrix_multiply(double** m1, double** m2, double** result, size_t size)
{
parallel_for (size_t(0), size, [&](size_t i)
{
for (size_t j = 0; j < size; j++)
{
double temp = 0;
for (int k = 0; k < size; k++)
{
temp += m1[i][k] * m2[k][j];
}
result[i][j] = temp;
}
});
}
這個範例只會平行處理外部迴圈,因為它會執行足夠的工作,以便從平行處理的額外負荷中獲益。如果您平行處理內部迴圈,就無法提升效能,因為內部迴圈所執行的少量工作不會克服平行處理的額外負荷。因此,在大部分的系統上,僅平行處理外部迴圈是充分發揮並行優勢的最佳途徑。
下列更完整的範例會比較 matrix_multiply 函式與 parallel_matrix_multiply 函式之間的效能差異。
// parallel-matrix-multiply.cpp
// compile with: /EHsc
#include <windows.h>
#include <ppl.h>
#include <iostream>
#include <random>
using namespace concurrency;
using namespace std;
// Calls the provided work function and returns the number of milliseconds
// that it takes to call that function.
template <class Function>
__int64 time_call(Function&& f)
{
__int64 begin = GetTickCount();
f();
return GetTickCount() - begin;
}
// Creates a square matrix with the given number of rows and columns.
double** create_matrix(size_t size);
// Frees the memory that was allocated for the given square matrix.
void destroy_matrix(double** m, size_t size);
// Initializes the given square matrix with values that are generated
// by the given generator function.
template <class Generator>
double** initialize_matrix(double** m, size_t size, Generator& gen);
// Computes the product of two square matrices.
void matrix_multiply(double** m1, double** m2, double** result, size_t size)
{
for (size_t i = 0; i < size; i++)
{
for (size_t j = 0; j < size; j++)
{
double temp = 0;
for (int k = 0; k < size; k++)
{
temp += m1[i][k] * m2[k][j];
}
result[i][j] = temp;
}
}
}
// Computes the product of two square matrices in parallel.
void parallel_matrix_multiply(double** m1, double** m2, double** result, size_t size)
{
parallel_for (size_t(0), size, [&](size_t i)
{
for (size_t j = 0; j < size; j++)
{
double temp = 0;
for (int k = 0; k < size; k++)
{
temp += m1[i][k] * m2[k][j];
}
result[i][j] = temp;
}
});
}
int wmain()
{
// The number of rows and columns in each matrix.
// TODO: Change this value to experiment with serial
// versus parallel performance.
const size_t size = 750;
// Create a random number generator.
mt19937 gen(42);
// Create and initialize the input matrices and the matrix that
// holds the result.
double** m1 = initialize_matrix(create_matrix(size), size, gen);
double** m2 = initialize_matrix(create_matrix(size), size, gen);
double** result = create_matrix(size);
// Print to the console the time it takes to multiply the
// matrices serially.
wcout << L"serial: " << time_call([&] {
matrix_multiply(m1, m2, result, size);
}) << endl;
// Print to the console the time it takes to multiply the
// matrices in parallel.
wcout << L"parallel: " << time_call([&] {
parallel_matrix_multiply(m1, m2, result, size);
}) << endl;
// Free the memory that was allocated for the matrices.
destroy_matrix(m1, size);
destroy_matrix(m2, size);
destroy_matrix(result, size);
}
// Creates a square matrix with the given number of rows and columns.
double** create_matrix(size_t size)
{
double** m = new double*[size];
for (size_t i = 0; i < size; ++i)
{
m[i] = new double[size];
}
return m;
}
// Frees the memory that was allocated for the given square matrix.
void destroy_matrix(double** m, size_t size)
{
for (size_t i = 0; i < size; ++i)
{
delete[] m[i];
}
delete m;
}
// Initializes the given square matrix with values that are generated
// by the given generator function.
template <class Generator>
double** initialize_matrix(double** m, size_t size, Generator& gen)
{
for (size_t i = 0; i < size; ++i)
{
for (size_t j = 0; j < size; ++j)
{
m[i][j] = static_cast<double>(gen());
}
}
return m;
}
下列是針對配備四個處理器之電腦的範例輸出。
serial: 3853
parallel: 1311
編譯程式碼
若要編譯的程式碼,將它複製然後將它貼在 Visual Studio 專案中,或將它貼在檔名為平行-矩陣-multiply.cpp ,然後執行下列命令,Visual Studio 的命令提示字元] 視窗中。
cl.exe /EHsc parallel-matrix-multiply.cpp