简体   繁体   English

在gcc中,使用ease(begin())从unordered_set中“删除一个元素”很慢

[英]“remove one element” from unordered_set using erase(begin()) is slow in gcc

I'd like to have a function to "remove one element" from unordered_set. 我想拥有一个功能,可以从unordered_set中“删除一个元素”。

However, when it's implemented using erase(begin()), it becomes extremely slow. 但是,当使用delete(begin())实现时,它变得非常慢。 (This is in g++-4.5.3; maybe begin() has to traverse a larger number of empty hash buckets?) (这在g ++-4.5.3中;也许begin()必须遍历大量的空哈希存储桶?)

See the example code below with surprising timings. 请参阅下面的示例代码,并给出令人惊讶的时序。

Is there some other way to implement "remove one element" that would have greater efficiency? 还有其他方法可以实现效率更高的“删除一个要素”吗? (I do want to allow other intervening set operations which would invalidate iterators.) (我确实想允许其他干预set操作,这些操作会使迭代器无效。)

#include <unordered_set>
#include <iostream>
#include <chrono>
using namespace std;

struct Timer {
    Timer(string s) : _s(s), _start(Clock::now()) { }
    ~Timer() {
        auto t=chrono::duration_cast<chrono::milliseconds>(Clock::now()-_start).count();
        cerr << "Timer(" << _s << ") = " << t << "ms\n";
    }
 private:
    typedef chrono::high_resolution_clock Clock;
    string _s;
    Clock::time_point _start;
};

int main()
{
    unordered_set<int> s;
    const int num=200000;
    { Timer t("insert"); for (int i=0;i<num;i++) { s.insert(i); } }
    { Timer t("remove half"); for (int i=0;i<num/2;i++) { s.erase(s.begin()); } }
    long long s1=0, s2=0;
    { Timer t("access begin()"); for (int i=0;i<num/2;i++) { s1+=*s.begin(); } }
    { Timer t("access all"); for (auto it=s.begin();it!=s.end();++it) { s2+=*it; } }
    cerr << s1 << " " << s2 << "\n";
    return 0;
}

// Timer(insert) = 36ms
// Timer(remove half) = 3039ms
// Timer(access begin()) = 5958ms
// Timer(access all) = 1ms

It looks like an issue with that version of the GNU library, fixed in more recent versions. 该版本的GNU库似乎存在问题,已在较新的版本中修复。 Here are the results of my tests, using the two versions I happen to have installed: 以下是我碰巧安装的两个版本的测试结果:

mikes@seymour-desktop:~$ g++-4.4.5 -std=c++0x -O3 test.cpp
mikes@seymour-desktop:~$ ./a.out 
Timer(insert) = 15ms
Timer(remove half) = 3815ms
Timer(access begin()) = 7722ms
Timer(access all) = 0ms
10000000000 14999950000

mikes@seymour-desktop:~$ g++-4.6.1 -std=c++0x -O3 test.cpp
mikes@seymour-desktop:~$ ./a.out 
Timer(insert) = 16ms
Timer(remove half) = 2ms
Timer(access begin()) = 0ms
Timer(access all) = 1ms
10000000000 14999950000

I also got similarly fast results by using boost::unordered_set , so that's an option if you can't update your compiler. 通过使用boost::unordered_set ,我也获得了类似的快速结果,因此,如果您无法更新编译器,则可以选择该选项。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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