我正在尝试编写一个函数,使用并行 for 循环将堆上的数组乘以一个常量,但是当尝试在设置了/Qpar-report:2 的 VisualStudio 2017 中进行编译时,我收到消息“由于“1000”的原因,循环未并行化。我查了一下,消息是“编译器在循环体中检测到数据依赖性。”:
文本描述了(例如)不同的传递依赖于其他传递的结果的情况,但这并不适用于此处。我能想到的唯一情况是优化器可能担心这两个数组在内存中重叠,但您如何说服编译器不是这种情况?
我尝试使用 #pragma ivdep 语句强制执行它,并且代码可以编译,但函数在调用时挂起。
经过多次故障排除后,我确定如果我在函数内部的堆栈上创建虚拟数组并对其进行循环,它会成功并行化。不幸的是,我不能依赖我将接受的数组小到足以将其完全复制到堆栈上。
我在 SO 和谷歌上查了其他并行执行简单数组操作的示例,它们都使用堆栈分配的数组。肯定有一种干净的方法来并行化堆数组上的操作??
#include "stdafx.h"
#include "CppUnitTest.h"
#include "../UnitsConversion/UnitsConversion.h"
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
#define ARRAY_SIZE 10000000
double* testInD;
double* testOutD;
namespace UnitTest
{
TEST_CLASS(Parallel)
{
public:
TEST_CLASS_INITIALIZE(setup) {
testInD = new double[ARRAY_SIZE];
testOutD = new double[ARRAY_SIZE];
for (int i = 0; i < ARRAY_SIZE; i++) {
testInD[i] = (double)rand() / (double)RAND_MAX;
testOutD[i] = (double)rand() / (double)RAND_MAX;
}
}
TEST_CLASS_CLEANUP(cleanup) {
delete testInD;
delete testOutD;
}
TEST_METHOD(PressuresD)
{
Assert::AreEqual(
(int)1,
PressureD(
testInD,
testOutD,
ARRAY_SIZE
)
);
}
}
int __stdcall PressureD(
double* dblInValue,
double* dblOutValue,
int n) {
#pragma loop(hint_parallel(0))
for (int i = 0; i < n; ++i) {
dblOutValue[i] = dblInValue[i] * 5.0;
}
return 1;
}
无论出于何种原因,我都无法通过 Google 或 SO 找到解决方案,尽管我认为这是一个常见问题。我错过了什么吗?
编辑:
将循环更改为以下确实允许它并行化:
for (int i = 0; i < n; ++i) {
//dblOutValue[i] = dblInValue[i] * factor; (old version)
dblOutValue[i] *= factor;
}
但是,当我尝试运行单元测试时,代码挂起并最终(大约 15 秒后)中止。当我在 Debug模式下运行代码时,它可以工作,但我 95% 确定那是因为它在 Debug模式下运行时没有并行化。
最佳答案
这是一个简单的新建/删除不匹配。您的单元测试有数组 new[]
和标量 delete
.
放弃手动内存管理并使用 std::unique_ptr<double[]>
或 std::vector<double>
.您可能需要在循环之前获取指向数据的裸指针(事实上,PressureD
根本不需要更改),以便并行化成功,但您不需要手动管理生命周期。
关于c++ - 如何自动并行化堆数组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54188105/