【问题标题】:C++ performance issues with std::map performance in A* path finding.A* 路径查找中 std::map 性能的 C++ 性能问题。
【发布时间】:2015-01-07 10:04:18
【问题描述】:

我目前正在学习 C++,因此我正在将我之前用 Python 编写的 A* 寻路算法转换为 C++。尽管对 C++ 库中所有不同类型的数据类型了解不多,但我还是决定投入其中。

完成程序编写后,C++ 版本的运行速度比 Python 版本慢(该程序使用 std::map 而不是 Python 字典来存储移动成本)。不管您是否知道寻路,是否有人可以查看我的代码并告诉它为什么运行效率如此低下?

我运行了 Visual Studios Profiler 来检查效率如此低下的原因(我知道队列可用于加快搜索速度,但请记住,在 Python 中使用相同的代码且没有优先级队列的情况下,它的运行速度要快 50 倍)..似乎几乎所有时间都被 std::map [] 运算符使用:

Function Name   Total CPU (%) -> 88.01 %
+ std::map<std::pair<int,int>,int,std::less<std::pair<int,int>>,
  std::allocator<std::pair<std::pair<int,int> const ,int> > >::
  operator[]

我的代码:

    void findPath(pair<int, int> startLocation, pair<int, int> endLocation){

    vector<pair<int, int>> openSet;
    vector<pair<int, int>> closedSet;
    openSet.push_back(startLocation);

    map<pair<int, int>, pair<int, int>> cameFrom;
    map<pair<int, int>, int> gCosts;
    map<pair<int, int>, int> fCosts;

    gCosts[startLocation] = 0;
    fCosts[startLocation] = heuristic(startLocation, endLocation);

    pair<int, int> currentNode;
    while (openSet.size() > 0){

        currentNode = openSet[0];

        for (std::vector<pair<int, int>>::iterator it = openSet.begin(); it != openSet.end(); ++it){
            pair<int, int> node = *it;
            if (fCosts[node] < fCosts[currentNode])
                currentNode = node;
        }

        if (DEBUG){
            cout << "Current Node: " << currentNode.first << " " << currentNode.second << endl;
        }

        if (currentNode == endLocation){
            break;
        }

        openSet.erase( remove(openSet.begin(), openSet.end(), currentNode), openSet.end() );
        closedSet.push_back(currentNode);

        vector<pair<int, int>> neighbors = getNeighbors(currentNode);

        for (std::vector<pair<int, int>>::iterator it = neighbors.begin(); it != neighbors.end(); ++it){
            pair<int, int> neighbor = *it;
            if (std::find(closedSet.begin(), closedSet.end(), neighbor) != closedSet.end()) {
                continue;
            }

            int possiblegCost = gCosts[currentNode] + heuristic(currentNode, neighbor);

            bool inOpenSet = find(openSet.begin(), openSet.end(), neighbor) != openSet.end();
            if (!inOpenSet || (possiblegCost < gCosts[neighbor])) {
                cameFrom[neighbor] = currentNode;
                gCosts[neighbor] = possiblegCost;
                fCosts[neighbor] = possiblegCost + heuristic(neighbor, endLocation);

                /*if (DEBUG){
                console() << "Modifying neighbor: " << neighbor.first << "," << neighbor.second << " Costs of: "
                << gCosts[neighbor] << " " << fCosts[neighbor] << endl;
                }*/

                if (!inOpenSet){
                    openSet.push_back(neighbor);
                }
            }

        }
    }

}

【问题讨论】:

  • 尝试使用std::unordered_map 而不是普通的旧std::map,它使用散列可以充分加快您的程序。
  • 您是否正在运行优化的构建?
  • @TartanLlama 可能值得一提的是,这还需要为std::pair&lt;int, int&gt; 添加一个特化,或者像我描述的here 那样指定一个散列函数。
  • 小微优化,但您可以将while (openSet.size() &gt; 0) 替换为while (!myset.empty())
  • 你为什么总是把自己定位在openSet[0]?当你找到一个成本较低的节点时,你push_back,所以它在向量的末尾。您并没有真正正确使用 C++。例如,在第二个for 循环中,您总是声明neighbour。在 C++ 中,这转换为:调用 pair 构造函数,它是 operator=。因此,微优化是将 pair 放在循环之前。

标签: c++ visual-c++ path-finding stdmap


【解决方案1】:

使用std::map::find 和/或std::map::emplace/std::map::emplace_hint 可能比std::map operator[] 快​​得多

【讨论】:

  • 在我看来,时间必须在阅读和编写现有条目;在内存分配上花费的时间很少。 (因此安置可能会有所帮助,但作用不大)。
  • @Matt McNabb operator [] ist 的问题在于它使用了默认构造、非默认构造和赋值的组合,尽管在大多数情况下单个就地构造就足够了,但我同意这可能对 ints 等内置数据类型没有多大帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-25
  • 2010-12-04
  • 2011-04-16
  • 1970-01-01
相关资源
最近更新 更多