我试图编写一个函数,使用并行的for循环,将堆上的数组乘以常量,但是当试图在Visual Studio 2017中使用/ Qpar-report:2设置编译时,我收到消息“循环由于原因“ 1000”而无法并行化。我对其进行了查找,并显示消息“编译器在循环体内检测到数据依赖性。”:
文本描述了(例如)不同的通行证取决于其他通行证的结果的情况,但此处不适用。我能想到的唯一情况是优化器可能会担心两个数组在内存中重叠,但是如何说服编译器不是这种情况呢?
我尝试使用#pragma ivdep语句强制执行该操作,并且代码可以编译,但是函数在调用时挂起。
经过大量的故障排除后,我确定如果在函数内部的堆栈上创建虚拟数组并对其进行循环,则可以成功并行化。不幸的是,我不能依靠我会接受的足够小的数组来完全复制到堆栈上。
我在SO和google上检查了并行执行类似简单数组操作的其他示例,它们都使用堆栈分配的数组。当然,有一种干净的方法可以并行处理堆数组上的操作?
#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秒后)中止。当我在调试模式下运行该代码时,该代码有效,但我95%的确信这是因为在调试中运行时,该代码不会并行化。
答案 0 :(得分:1)
这是一个简单的新/删除不匹配。您的单元测试具有数组new[]
和标量delete
。
放弃手动内存管理,并使用std::unique_ptr<double[]>
或std::vector<double>
。为了使并行化成功,您可能需要在循环之前获取一个指向数据的裸露指针(实际上,PressureD
根本不需要更改),但是您无需手动管理生命周期