[英]Intel TBB parallel_reduce returning incorrect result
我正在尝试使用英特尔TBB parallel_reduce来计算对Connect 4游戏中用户移动的最佳响应。 我写了一个简单的函数,当传递一个列号时,返回一个与播放该移动的效用相对应的启发式分数。 我的意图是并行调用此函数,然后返回返回结果的减少。 减少将是具有最高启发式分数的移动。
但是我发现我的结果不一致。 我希望第0列的移动可以从并行缩减中返回(因为我已经编写了启发式分数函数,因此它返回7 - 列号作为分数)。
我附上了C ++代码。 以下是它生成的示例输出:
返回0
返回1
回归2
回归6
回归4
回归5
比较移动5返回移动3和6
比较移动3和4
比较移动3和5
比较移动2和3
最佳举措是2
我已多次查看代码并且无法理解为什么它并不总是返回0作为最佳移动。 它有时会返回零,但并非总是如此。 如上所示,移动0被评估,但是简化lambda函数永远不会将其作为输入。 任何帮助将不胜感激。 我有一种模糊的怀疑,即我所使用的0的身份,可能不对。 但是我不确定它应该是什么。
#include <tbb\blocked_range.h>
#include <tbb\parallel_reduce.h>
#include <iostream>
#include <vector>
int getMoveHueristicScore(int columnCounter) {
int returnValue = 7 - columnCounter;
return returnValue;
}
int bestHeuristicScore(int numberOfColumns) {
std::vector<int> moveScores(numberOfColumns, -1 * INT_MAX);
return tbb::parallel_reduce(
tbb::blocked_range<int>(0, numberOfColumns),
0,
[=, &moveScores](const tbb::blocked_range<int>& range, int bestMove)->int {
int bestScore = -1 * INT_MAX;
for (int columnCounter = range.begin(); columnCounter != range.end(); ++columnCounter) {
moveScores.at(columnCounter) = getMoveHueristicScore(columnCounter);
if (moveScores.at(columnCounter) > bestScore) {
bestScore = moveScores.at(columnCounter);
bestMove = columnCounter;
}
}
std::cout << "Return move " << bestMove << std::endl;
return bestMove;
},
[=, &moveScores](int bestMove1, int bestMove2)->int {
std::cout << "Compare moves " << bestMove1 << " & " << bestMove2 << std::endl;
if (moveScores.at(bestMove1) > moveScores.at(bestMove2)) {
return bestMove1;
}
else {
return bestMove2;
}
}
);
}
int main() {
int bestMove = bestHeuristicScore(7);
std::cout << "Best move is " << bestMove << std::endl;
return 0;
}
在这种情况下, tbb::parallel_reduce
没有问题。 问题是您的代码忽略了func
函数的init
参数。
TBB对如何进行减少有不同的选择。 它可以选择为不同线程中的不同子范围调用func
,然后使用reduction
函数组合结果; 它可以在同一个线程中多次调用func
,每次传入前一次调用的结果; 或者它可以结合使用这两种策略。
看看你的func
实现:
[=, &moveScores](const tbb::blocked_range<int>& range, int bestMove)->int {
int bestScore = -1 * INT_MAX;
for (int columnCounter = range.begin(); columnCounter != range.end(); ++columnCounter) {
moveScores.at(columnCounter) = getMoveHueristicScore(columnCounter);
if (moveScores.at(columnCounter) > bestScore) {
bestScore = moveScores.at(columnCounter);
bestMove = columnCounter;
}
}
std::cout << "Return move " << bestMove << std::endl;
return bestMove;
}
从不使用init
参数bestMove
; 相反,将bestScore
值初始化为某个虚拟值。 TBB可以多次调用func
,每次都从前一次调用中传入计算的bestMove
,但是这会被忽略,因此最终结果将是从传递给最后一次调用的bestMove
范围中的最佳结果。
修复方法是使用bestMove
初始化最佳分数,如下所示:
int bestScore = moveScores.at(bestMove);
然后TBB将从一次func
调用到下一次调用运行最佳分数,确保最终结果确实是全局最佳分数。
您声称减少的左侧身份是0
,显然不是这种情况。 您必须提供此类身份,并在减速器中处理。 尝试-1
并明确处理它。
并且-INT_MAX
关闭1。
在遇到错误时明确捕获(删除=
)。 了解捕获的内容有时会有很大帮助。
令我感到惊讶的是你的样本输出没有提到1
减少,但我并不感到惊讶的是缺少0
。
您正在从多个线程访问std::vector
,这是不安全的。 这可能是您问题的根源。 将moveScores
容器更改为tbb::concurrent_vector<int>
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.