[英]priority_queue becomes extremely slow in debug mode
我目前正在為游戲編寫A *尋路算法,並且遇到了與priority_queue有關的非常奇怪的性能問題 。
我使用的是典型的“開放節點列表”,在其中存儲找到的但尚未處理的節點。 這被實現為指向PathNodeRecord對象的指針的STL priority_queue ( openList ),該指針存儲有關訪問的節點的信息。 它們按到達那里的估計成本( estimateTotalCost )進行排序。
現在我注意到,每當調用尋路方法時,相應的AI線程就會完全卡住,並花費幾(〜5)秒來處理算法並計算路徑。 隨后,我使用VS2013分析器查看了花了這么長時間的原因,原因和地點。
事實證明, 推送到打開列表 (priority_queue) 和從打開列表中彈出會花費大量時間。 我不是STL容器的專家,但是我以前從未對它們的效率有任何疑問,這對我來說很奇怪。
奇怪的是,這僅在使用VS的“調試”構建配置時發生。 “發布”會議。 對我來說效果很好,現在一切恢復正常了。
我在這里做的事情根本上是錯的,還是為什么priority_queue對我來說如此糟糕? 當前的情況對我來說是無法接受的,因此,如果我不能盡快解決它,我將不得不退一步,使用一個更簡單的容器並將其手動插入正確的位置。
任何可能導致這種情況發生的指示都將非常有幫助!
。
以下是分析器向我顯示的內容的摘要:
http://i.stack.imgur.com/gEyD3.jpg
。
這是尋路算法的相關部分,它將循環打開列表,直到沒有打開的節點為止:
// set up arrays and other variables
PathNodeRecord** records = new PathNodeRecord*[graph->getNodeAmount()]; // holds records for all nodes
std::priority_queue<PathNodeRecord*> openList; // holds records of open nodes, sorted by estimated rest cost (most promising node first)
// null all record pointers
memset(records, NULL, sizeof(PathNodeRecord*) * graph->getNodeAmount());
// set up record for start node and put into open list
PathNodeRecord* startNodeRecord = new PathNodeRecord();
startNodeRecord->node = startNode;
startNodeRecord->connection = NULL;
startNodeRecord->closed = false;
startNodeRecord->costToHere = 0.f;
startNodeRecord->estimatedTotalCost = heuristic->estimate(startNode, goalNode);
records[startNode] = startNodeRecord;
openList.push(startNodeRecord);
// ### pathfind algorithm ###
// declare current node variable
PathNodeRecord* currentNode = NULL;
// loop-process open nodes
while (openList.size() > 0) // while there are open nodes to process
{
// retrieve most promising node and immediately remove from open list
currentNode = openList.top();
openList.pop(); // ### THIS IS, WHERE IT GETS STUCK
// if current node is the goal node, end the search here
if (currentNode->node == goalNode)
break;
// look at connections outgoing from this node
for (auto connection : graph->getConnections(currentNode->node))
{
// get end node
PathNodeRecord* toNodeRecord = records[connection->toNode];
if (toNodeRecord == NULL) // UNVISITED -> path record needs to be created and put into open list
{
// set up path node record
toNodeRecord = new PathNodeRecord();
toNodeRecord->node = connection->toNode;
toNodeRecord->connection = connection;
toNodeRecord->closed = false;
toNodeRecord->costToHere = currentNode->costToHere + connection->cost;
toNodeRecord->estimatedTotalCost = toNodeRecord->costToHere + heuristic->estimate(connection->toNode, goalNode);
// store in record array
records[connection->toNode] = toNodeRecord;
// put into open list for future processing
openList.push(toNodeRecord);
}
else if (!toNodeRecord->closed) // OPEN -> evaluate new cost to here and, if better, update open list entry; otherwise skip
{
float newCostToHere = currentNode->costToHere + connection->cost;
if (newCostToHere < toNodeRecord->costToHere)
{
// update record
toNodeRecord->connection = connection;
toNodeRecord->estimatedTotalCost = newCostToHere + (toNodeRecord->estimatedTotalCost - toNodeRecord->costToHere);
toNodeRecord->costToHere = newCostToHere;
}
}
else // CLOSED -> evaluate new cost to here and, if better, put back on open list and reset closed status; otherwise skip
{
float newCostToHere = currentNode->costToHere + connection->cost;
if (newCostToHere < toNodeRecord->costToHere)
{
// update record
toNodeRecord->connection = connection;
toNodeRecord->estimatedTotalCost = newCostToHere + (toNodeRecord->estimatedTotalCost - toNodeRecord->costToHere);
toNodeRecord->costToHere = newCostToHere;
// reset node to open and push into open list
toNodeRecord->closed = false;
openList.push(toNodeRecord); // ### THIS IS, WHERE IT GETS STUCK
}
}
}
// set node to closed
currentNode->closed = true;
}
這是我的PathNodeRecord,帶有“ less”運算符的重載以啟用在priority_queue中的排序:
namespace AI
{
struct PathNodeRecord
{
Node node;
NodeConnection* connection;
float costToHere;
float estimatedTotalCost;
bool closed;
// overload less operator comparing estimated total cost; used by priority queue
// nodes with a higher estimated total cost are considered "less"
bool operator < (const PathNodeRecord &otherRecord)
{
return this->estimatedTotalCost > otherRecord.estimatedTotalCost;
}
};
}
std::priority_queue<PathNodeRecord*> openList
我想原因是,你有一個priority_queue
指針的PathNodeRecord
。 並且沒有為指針定義順序。
嘗試首先將其更改為std::priority_queue<PathNodeRecord>
,如果有區別,那么您所需要的只是傳遞自己的比較器,該比較器知道如何比較指向PathNodeRecord
指針,它將首先取消引用指針,然后進行比較。
編輯:瘋狂猜測您為什么會得到極慢的執行時間,我認為指針是根據其地址進行比較的。 從內存中的一點開始分配地址,然后遞增。 這樣就導致了堆的極端情況(數據結構中的堆而不是內存部分),因此堆實際上是一個列表(一棵樹,其中每個節點都有一個子節點,依此類推)。 因此您的操作花費了線性時間,再次只是一個猜測。
您不能指望調試版本會像經過發行版優化的版本一樣快,但是您似乎進行了很多動態分配,這些動態分配可能會與調試運行時發生嚴重的交互。
我建議您在項目的調試屬性頁的環境設置中添加_NO_DEBUG_HEAP=1
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.