元の問題:
そこで、スレッドを使って実験し、いくつかのテストを行うコードをいくつか書きました。
コードはいくつかの数値を作成し、それらの数値の平均を見つける必要があります。
私がこれまでに持っているものをお見せする方が簡単だと思います。コードが約 2 倍速く実行される 2 つのスレッドで期待していました。ストップウォッチで測ってみると 6倍ぐらい遅くなってる気がします!編集:現在、コンピューターと clock() 関数を使用して時間を伝えています。
void findmean(std::vector<double>*, std::size_t, std::size_t, double*);
int main(int argn, char** argv)
{
// Program entry point
std::cout << "Generating data..." << std::endl;
// Create a vector containing many variables
std::vector<double> data;
for(uint32_t i = 1; i <= 1024 * 1024 * 128; i ++) data.push_back(i);
// Calculate mean using 1 core
double mean = 0;
std::cout << "Calculating mean, 1 Thread..." << std::endl;
findmean(&data, 0, data.size(), &mean);
mean /= (double)data.size();
// Print result
std::cout << " Mean=" << mean << std::endl;
// Repeat, using two threads
std::vector<std::thread> thread;
std::vector<double> result;
result.push_back(0.0);
result.push_back(0.0);
std::cout << "Calculating mean, 2 Threads..." << std::endl;
// Run threads
uint32_t halfsize = data.size() / 2;
uint32_t A = 0;
uint32_t B, C, D;
// Split the data into two blocks
if(data.size() % 2 == 0)
{
B = C = D = halfsize;
}
else if(data.size() % 2 == 1)
{
B = C = halfsize;
D = hsz + 1;
}
// Run with two threads
thread.push_back(std::thread(findmean, &data, A, B, &(result[0])));
thread.push_back(std::thread(findmean, &data, C, D , &(result[1])));
// Join threads
thread[0].join();
thread[1].join();
// Calculate result
mean = result[0] + result[1];
mean /= (double)data.size();
// Print result
std::cout << " Mean=" << mean << std::endl;
// Return
return EXIT_SUCCESS;
}
void findmean(std::vector<double>* datavec, std::size_t start, std::size_t length, double* result)
{
for(uint32_t i = 0; i < length; i ++) {
*result += (*datavec).at(start + i);
}
}
このコードが素晴らしいとは思いません。改善方法を提案していただければ、それもありがたいです。
レジスタ変数:
関数「findmean」のローカル変数を作成することを提案する人が何人かいます。これは私がやったことです:
void findmean(std::vector<double>* datavec, std::size_t start, std::size_t length, double* result)
{
register double holding = *result;
for(uint32_t i = 0; i < length; i ++) {
holding += (*datavec).at(start + i);
}
*result = holding;
}
私は今報告することができます: コードは、シングル スレッドとほぼ同じ実行時間で実行されます。これは 6 倍の大幅な改善ですが、2 倍近く速くする方法があるに違いありません。
変数と O2 の最適化を登録します。
最適化を「O2」に設定しました。結果を含むテーブルを作成します。
これまでの結果:
最適化またはレジスタ変数のない元のコード: 1 スレッド: 4.98 秒、2 スレッド: 29.59 秒
レジスター変数を追加したコード: 1 スレッド: 4.76 秒、2 スレッド: 4.76 秒
reg 変数と -O2 最適化の場合: 1 スレッド: 0.43 秒、2 スレッド: 0.6 秒2 スレッドは遅くなりましたか?
2 つの結果変数の間に大きなメモリ ブロックを配置するという Dameon の提案: 1 スレッド: 0.42 秒、2 スレッド: 0.64 秒
ベクトルの内容にアクセスするために反復子を使用する TAS の提案: 1 スレッド: 0.38 秒、2 スレッド: 0.56 秒
上記と同じ Core i7 920 (シングル チャネル メモリ 4GB): 1 スレッド: 0.31 秒、2 スレッド: 0.56 秒
上記と同じ Core i7 920 (デュアル チャネル メモリ 2x2GB): 1 スレッド: 0.31 秒、2 スレッド: 0.35 秒