繁体   English   中英

Intel TBB parallel_reduce返回错误的结果

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM