我正在尝试使用英特尔TBB parallel_reduce来计算对Connect 4游戏中用户移动的最佳响应。我写了一个简单的函数,当传递一个列号时,返回一个与播放该移动的效用相对应的启发式分数。我的意图是并行调用此函数,然后返回返回结果的减少。减少将是具有最高启发式分数的移动。
然而,我发现结果不一致。我希望第0列的移动可以从并行缩减中返回(因为我已经编写了启发式分数函数,因此它返回7 - 列号作为分数)。
我附上了C ++代码。以下是它生成的示例输出:
返回0
返回移动1
返回举动2
返回举动6
返回移动4
返回举动5
比较动作5Return move 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;
}
答案 0 :(得分:3)
在这种情况下,tbb::parallel_reduce
没有问题。问题是您的代码忽略了init
函数的func
参数。
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
的一次调用中获得最佳分数,确保最终结果确实是全球最佳分数。
答案 1 :(得分:0)
您声称缩减的左侧身份是0
,显然不是这种情况。您必须提供此类身份,并在减速器中处理。尝试-1
并明确处理它。
并且-INT_MAX
关闭了1。
在遇到错误时明确捕获(删除=
)。了解捕获的内容有时会有很大帮助。
我很惊讶您的示例输出在减少时没有提及1
,但我对0
的缺失并不感到惊讶。
答案 2 :(得分:0)
您正在从多个线程访问std::vector
,这是不安全的。这可能是您问题的根源。将您的moveScores
容器更改为tbb::concurrent_vector<int>
。