【发布时间】:2025-11-25 06:30:01
【问题描述】:
我正在比较 STL (g++) priority_queue 的性能,发现 push 和 pop 没有我预期的那么快。见以下代码:
#include <set>
#include <queue>
using namespace std;
typedef multiset<int> IntSet;
void testMap()
{
srand( 0 );
IntSet iSet;
for ( size_t i = 0; i < 1000; ++i )
{
iSet.insert(rand());
}
for ( size_t i = 0; i < 100000; ++i )
{
int v = *(iSet.begin());
iSet.erase( iSet.begin() );
v = rand();
iSet.insert(v);
}
}
typedef priority_queue<int> IntQueue;
void testPriorityQueue()
{
srand(0);
IntQueue q;
for ( size_t i = 0; i < 1000; ++i )
{
q.push(rand());
}
for ( size_t i = 0; i < 100000; ++i )
{
int v = q.top();
q.pop();
v = rand();
q.push(v);
}
}
int main(int,char**)
{
testMap();
testPriorityQueue();
}
我编译了这个 -O3 然后运行 valgrind --tool=callgrind, KCachegrind testMap 占用总 CPU 的 54% testPriorityQueue 占用 44% 的 CPU
(没有-O3 testMap比testPriorityQueue快很多) testPriorityQueue 似乎花费了大部分时间的函数被调用
void std::__adjust_heap<__gbe_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, long, int, std::less<int> >
该函数似乎是从 pop() 调用中调用的。
这个函数具体做什么?有没有办法通过使用不同的容器或分配器来避免它?
【问题讨论】:
-
堆缓存不友好吗?至少这是我的总体印象。
-
而且我认为它们以不可预知的方式分支很多。该函数看起来是负责堆“冒泡”的原因,这是每次删除元素以维持其顺序时必须在堆上执行的 log(n) 操作。
-
CPU% 不是测试性能或速度的有用方法。
__adjust_heap“重新平衡”优先级队列,是处理优先级队列时唯一缓慢的操作。这是优先队列所固有的,我能想到的唯一选择是std::set,它必须以类似的方式平衡。 -
我今天下午做了一个简单的priority_queue模板,在Linux 64位编译-O3时几乎是std::priority_queue的两倍。
标签: c++ performance stl priority-queue multiset