OpenMP,循环并行,处理时间差异大
OpenMP, parallel for loop, Large differences in processing time
我开发了一个程序,可以从.txt文件中读取数字,并将其存储到一个向量中,经过一系列组合和计算,以确定结果是否与我想要的数字匹配。这些过程将在多个线程中完成,其中每个线程将负责处理并行for循环中的各种迭代次数。
长话短说,当涉及到大数字(例如9个数字)时,处理时间变化很大,其中处理时间可能短至3分钟,也可能超过10分钟。
以下是我迄今为止尝试过的基准:
8 numbers serial : 18.119 seconds
8 numbers multithread (first-try): 10.238 seconds
8 numbers multithread (second-try): 18.943 seconds
9 numbers serial : 458.980 seconds
9 numbers multithread (first-try): 172.347 seconds
9 numbers multithread (second-try): 519.532 seconds //Seriously?
//Another try after suggested modifications
9 numbers multithread (first-try): 297.017 seconds
9 numbers multithread (second-try): 297.85 seconds
9 numbers multithread (third-try): 304.755 seconds
9 numbers multithread (fourth-try): 396.391 seconds
因此,问题是,是否有任何可能的方法来改进程序(多线程),使其只需要最少的时间来打乱/计算数字?
以下是发生并行for循环的代码部分(经过轻微修改后更新):
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <stdlib.h>
#include <algorithm>
#include <stdio.h>
#include <Windows.h>
#include <omp.h>
#define OPERATORSIZE 3
using namespace std;
int cur_target;
ofstream outFile;
string get_operator(int i) {
switch (i) {
case 0:
return "+";
case 1:
return "-";
case 2:
return "*";
case 3:
return "/";
default:
return "";
}
}
int prev_num_pos(vector<int> &cur_equation, int count) {
for (int i = count - 1; i >= 0; i--) {
if (cur_equation[i] != -1) return i + 1;
}
return 0;
}
bool nextoperator(int k, vector<int> &operator_array) {
for (int i = k - 2; i >= 0; i--) {
if (operator_array[i] < OPERATORSIZE) {
operator_array[i] += 1;
break;
}
else
operator_array[i] = 0;
switch (i) {
case 0:
return false;
}
}
return true;
}
void vector_combination(vector<int> int_list) { // Generate the number combinations from the number list
bool div_remainder = false;
int count = 0;
#pragma omp parallel for schedule(dynamic) firstprivate(div_remainder) reduction(+:count)
for (int i = 0; i < int_list.size(); ++i) {
vector<int> cur_equation, cur_temp, cur_list, operator_array;
auto list = int_list;
rotate(list.begin(), list.begin() + i, list.begin() + i + 1);
do
{
cur_list.clear();
operator_array.clear();
for (auto x : list)
cur_list.push_back(x);
for (int i = 0; i < cur_list.size() - 1; i++)
operator_array.push_back(0);
do
{
div_remainder = false;
count = 0;
cur_equation = operator_array;
cur_temp = cur_list;
for (int i = 0; i < cur_equation.size(); ++i) { // Check for equation priorities
if (cur_equation[i] == 3) {
count = i;
if (cur_temp[count] % cur_temp[count + 1] != 0) {
div_remainder = true;
break;
}
}
}
if (div_remainder)
continue;
for (int i = 0; i < cur_temp.size() - 1; ++i) {
count = -1;
if (cur_equation[i] == 2 || cur_equation[i] == 3) {
count = prev_num_pos(cur_equation, i);
}
else
continue;
if (cur_equation[i] == 2) {
cur_temp[count] *= cur_temp[i + 1];
cur_equation[i] = -1;
}
else if (cur_equation[i] == 3) {
if (cur_temp[i + 1] != 0) {
cur_temp[count] /= cur_temp[i + 1];
cur_equation[i] = -1;
}
else {
div_remainder = true;
break;
}
}
}
if (div_remainder)
continue;
for (int i = 0; i < cur_temp.size() - 1; ++i) {
switch (cur_equation[i]) {
case 0: {
cur_temp[0] += cur_temp[i + 1]; // Addition
cur_equation[i] = -1;
break;
}
case 1: { // Subtraction
cur_temp[0] -= cur_temp[i + 1];
cur_equation[i] = -i;
break;
}
}
}
if (cur_temp[0] == cur_target) {
#pragma omp critical
{
for (int i = 0; i < cur_list.size(); ++i) {
outFile << cur_list[i];
if (i < cur_list.size() - 1) { outFile << get_operator(operator_array[i]); }
}
outFile << "n";
}
}
} while (nextoperator(cur_list.size(), operator_array));
// Send to function to undergone a list of operator combinations
} while (next_permutation(list.begin() + 1, list.end()));
}
}
int main(void) {
SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
vector<int> int_list;
string line;
ifstream myfile("Problem.txt");
if (myfile.is_open()) {
while (getline(myfile, line)) {
int num = stoi(line);
int_list.push_back(num);
cur_target = num;
}
}
else
cout << "Unable to open file." << endl;
myfile.close();
int_list.pop_back();
sort(int_list.begin(), int_list.end());
outFile.open("answerswer.txt");
vector_combination(int_list);
outFile.close();
int answer_count = 0;
myfile.open("answerswer.txt");
if (myfile.is_open()) {
while (getline(myfile, line)) {
++answer_count;
if (answer_count > 1)
break;
}
}
myfile.close();
if (answer_count == 0) {
outFile.open("answerswer.txt");
outFile << "-1" << endl;
}
outFile.close();
return 0;
}
至于样本输入,创建一个名为"Problem.txt"的.txt文件,其中包含这样的随机数(最后一个数字是目标结果)(更新为用于基准测试的当前样本输入):
28
55
78
77
33
65
35
62
19
221
程序运行的硬件/软件规范:处理器:i5 Sandy Bridge 2500K,Ram:8GB,操作系统:Windows 10专业版,IDE:Visual Studio 2015 Enterprise Edition,
在if条件内移动#pragma omp critical
。由于cur_temp
是线程专用的,而cur_target
是全局只读的,因此没有必要用关键节来保护条件。这一变化极大地减少了线程之间的直接交互,并且在我的系统上,始终如一地加快了并行版本的速度。
我只能微弱地猜测性能变化受到不同线程上运行的循环之间的相移(看似随机)的影响。
如果性能变化仍然存在,请尝试启用线程绑定。查看OpenMP实现的文档,查找OMP_PROC_BIND
、"线程固定"、"绑定"或"亲和性"。
显然,运行时的差异是由向量引起的。我使用性能分析器对其进行了检查,并注意到在向量之间复制值所花费的时间不一致。我已经将它修改为指针数组,运行时现在得到了极大的改进和一致性。
- C++17中的并行执行策略
- 并行用于C++17中数组索引范围内的循环
- 如何在Elixir中调用递归函数并行
- OpenMP:并行更新数组总是需要减少数组吗
- 如何使用OpenMP并行这两个循环
- 如何使用OpenMP并行化此矩阵时间矢量运算
- 如何使用OpenMP使这个循环并行
- 遍历并行数组以确定C++中的最大数字
- 为什么 openmp 的并行不适用于矢量化色彩空间转换?
- 如何在 Mac 上使用 c++17 并行标准库算法?
- 并行标准::复制复杂性
- 如何使用 MPI 的远程内存访问 (RMA) 功能并行化数据聚合?
- 在C++中使用并行化的预期速度是多少(不是 OpenMp,而是 <thread>)
- 如何在 C++17 STL 并行算法中处理调度?
- OpenMP 与有序和关键指令并行
- OpenMP for 循环并行性问题
- 两个连续的 OpenMP 并行区域会相互减慢速度
- C++17:如何在并行 STL 中获取工作项的索引
- 如何使用 OpenMP 并行化最近邻搜索
- 如何使用 winsock2 实现与 c++ 的多个并行连接?