【发布时间】:2019-01-14 19:41:39
【问题描述】:
我正在尝试编写一个函数,将堆上的数组乘以一个常数,使用并行 for 循环,但是当尝试在 VisualStudio 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% 确定这是因为在调试模式下运行时它没有并行化。
【问题讨论】:
-
你试过
__restrict吗? -
我没听说过这个关键字!我试过了,代码在编译时确实并行化了,但是当我运行它时,单元测试仍然挂起并最终中止。
标签: c++ visual-studio performance parallel-processing x86