原文:http://blog.chinaunix.net/uid-20384806-id-3055333.html
测试条件:
gcc version 4.2.1 20070719? [
FreeBSD]
FreeBSD ?7.2-RELEASE #0: Fri May? 1 07:18:07 UTC 2009???? root@driscoll.cse.buffalo.edu:/usr/obj/usr/src/sys/GENERIC? amd64
Intel(R) Xeon(R) CPU?????????? E5620? @ 2.40GHz 16核
?
测试程序说明:
先准备好n个字符串随机的MD5字符串做为key,然后分别对3个容器进行插入、遍历、查找、
caozuo.html" target="_blank">删除操作。
例如,n=100的时候,插入是指插入100个随机MD5 key;遍历是指对容器遍历一次;查找是指分别对这个100个随机的MD5 key做查找操作(即查找100次);删除是指挨个删除这个100个随机MD5 key。
?
测试数据如下表:
插入,单位us
100
1K
10K
100K
1M
10M
std::map
241
2833
35888
381214
4439088
62233380
std::ext/
hash_map
97
1667
16466
146025
1788446
18512639
std::tr1::unordered_map
77
772
8052
53094
658312
7429297
?
遍历,单位us
100
1K
10K
100K
1M
10M
std::map
11
76
842
11603
155700
1771906
std::ext/hash_map
47
430
4218
39880
470344
4781575
std::tr1::unordered_map
1
1
2
1
2
1
查找,单位us
100
1K
10K
100K
1M
10M
std::map
156
2111
30456
258709
4100260
59064394
std::ext/hash_map
77
774
8056
56974
660231
7705527
std::tr1::unordered_map
77
772
8051
54456
659537
7600263
删除,单位us
100
1K
10K
100K
1M
10M
std::map
291
3641
49584
472414
6675897
92491113
std::ext/hash_map
89
869
9068
86524
964767
10372650
std::tr1::unordered_map
49
480
4879
33087
395098
4369617
结论:
1. std::tr1::unordered_map 与?std::ext/hash_map?
? ? ?任何情况下,如果要在这两个容器之间选择的话,
我们毫不犹豫应该选择 unordered_map。因为他的性能在上述4中操作中均优于 hash_map,甚至可以说远远优于 hash_map。
?
2.?
std::tr1::unordered_map 与?std::map?
? ? ?map的性能总体来说是最差的。但是,
当我们需要一个有序的关联容器的时候,我们必须选择std::map,因为?unordered_map?内部元素不是有序的,这一点从名字都可以看出来。除此之外都应该选择?unordered_map?。
?
3. 上述测试中,unordered_map?的遍历性能几乎是常数级别的,与常识不太相符,需要再
研究研究。
?
附录:贴上源代码
说明:与测试程序稍有区别,这里的源码里没有MD5相关的代码以确保其他人能比较方便的直接拿去编译运行。
?
如有
错误还请跟帖指出,非常感谢。
?
?
class="dp-css" style="margin-right: 1px; margin-bottom: 0px; margin-left: 1px; color: #5c5c5c; line-height: 1.3;">
- #include?<iostream>
- #include?<string>
- #include?<sstream>
- #include?<list>
- #include?<map>
- #include?<sys/time.h>
- #include?<ext/hash_map>
- #include?<tr1/unordered_map>
-
- namespace zl
-
{?//{{{
- ????struct equal_to
- ????{
- ????????bool operator()(const?char*?s1,?const?char*?s2)?const
- ????????{
- ????????????return strcmp(s1,?s2)?==?0;
- ????????}
- ????};
- ?
- ????struct hash_string
- ????????:?public?std::unary_function<std::string,?std::size_t>
- ????????{
- ????????????std::size_t
- ????????????????operator()(const?std::string&?__s)?const
- #ifdef __linux__
- ????????????????{?return std::tr1::Fnv_hash<>::hash(__s.data(),?__s.length());?}
- #else
- ????????????????{?return std::tr1::_Fnv_hash<>::hash(__s.data(),?__s.length());?}
- #endif
- ????????};
-
- ????
- ????struct hash_charptr
- ????????:?public?std::unary_function<const?char*,?std::size_t>
- ????????{
- ????????????std::size_t
- ????????????????operator()(const?char*?__s)?const
- #ifdef __linux__
- ????????????????{?return std::tr1::Fnv_hash<>::hash(__s,?strlen(__s));?}
- #else
- ????????????????{?return std::tr1::_Fnv_hash<>::hash(__s,?strlen(__s));?}
- #endif
- ????????};
-
}//}}}
-
- typedef std::list<std::string>?string_list;
- typedef std::map<std::string,?int>?string_map;
- typedef __gnu_cxx::hash_map<std::string,?int,?zl::hash_string>?string_hash_map;
- typedef std::tr1::unordered_map<std::string,?int>?string_unordered_map;
-
- void fill_list(string_list&?slist,?size_t count);
- uint64_t current_usec();
-
-
int?main(?int?argc,?char*?argv[]?)
- {
- ????if?(argc?!=?2?&&?argc?!=?3)
- ????{
- ????????fprintf(stderr,?"Usage:%s test_count rehash\n",?argv[0]);
- ????????fprintf(stderr,?"For example:%s 10000 rehash\n",?argv[0]);
- ????????return?-1;
- ????}
-
- ????size_t count?=?atoi(argv[1]);
- ????bool rehash?=?false;
- ????if?(argc?==?3)
- ????{
- ????????rehash?=?true;
- ????}
-
- ????string_map smap;
- ????string_hash_map shash_map;
- ????string_unordered_map sunordered_map;
-
- ????if?(rehash)
- ????{
- ????????sunordered_map.rehash(count);
- ????}
-
- ????string_list slist;
- ????fill_list(slist,?count);
-
- ????uint64_t start?=?0;
- ????uint64_t?end?=?0;
-
- ????uint64_t map_insert_us?=?0;
- ????uint64_t hash_map_insert_us?=?0;
- ????uint64_t unordered_map_insert_us?=?0;
-
- ????uint64_t map_traverse_us?=?0;
- ????uint64_t hash_map_traverse_us?=?0;
- ????uint64_t unordered_map_traverse_us?=?0;
-
- ????uint64_t map_find_us?=?0;
- ????uint64_t hash_map_find_us?=?0;
- ????uint64_t unordered_map_find_us?=?0;
-
- ????uint64_t map_delete_us?=?0;
- ????uint64_t hash_map_delete_us?=?0;
- ????uint64_t unordered_map_delete_us?=?0;
-
-
-
- ????//?Insert test
- ????{//{{{
- ????????string_list::iterator it(slist.begin());
- ????????string_list::iterator ite(slist.end());
-
- ????????//map insert
- ????????start?=?current_usec();
- ????????for?(int?i?=?0;?it?!=?ite;?++it,?++i)
- ????????{
- ????????????smap[*it]?=?i;
- ????????}
- ????????end?=?current_usec();
- ????????map_insert_us?=?end?-?start;
-
- ????????//hash_map insert
- ????????it?=?slist.begin();
- ????????start?=?current_usec();
- ????????for?(int?i?=?0;?it?!=?ite;?++it,?++i)
- ????????{
- ????????????shash_map[*it]?=?i;
- ????????}
- ????????end?=?current_usec();
- ????????hash_map_insert_us?=?end?-?start;
-
- ????????//unordered_map insert
- ????????it?=?slist.begin();
- ????????start?=?current_usec();
- ????????for?(int?i?=?0;?it?!=?ite;?++it,?++i)
- ????????{
- ????????????shash_map[*it]?=?i;
- ????????}
- ????????end?=?current_usec();
- ????????unordered_map_insert_us?=?end?-?start;
- ????}//}}}
-
- ????//?Traverse test
- ????{//{{{
- ????????//map traverse?
- ????????{
- ????????????string_map::iterator it(smap.begin());
- ????????????string_map::iterator ite(smap.end());
- ????????????start?=?current_usec();
- ????????????for?(int?i?=?0;?it?!=?ite;?++it)
- ????????????{
- ????????????????i++;
- ????????????}
- ????????????end?=?current_usec();
- ????????????map_traverse_us?=?end?-?start;
- ????????}
-
- ????????//hash_map traverse?
- ????????{
- ????????????string_hash_map::iterator it(shash_map.begin());
- ????????????string_hash_map::iterator ite(shash_map.end());
- ????????????start?=?current_usec();
- ????????????for?(int?i?=?0;?it?!=?ite;?++it)
- ????????????{
- ????????????????i++;
- ????????????}
- ????????????end?=?current_usec();
- ????????????hash_map_traverse_us?=?end?-?start;
- ????????}
-
- ????????//unordered_map traverse?
- ????????{
- ????????????string_unordered_map::iterator it(sunordered_map.begin());
- ????????????string_unordered_map::iterator ite(sunordered_map.end());
- ????????????start?=?current_usec();
- ????????????for?(int?i?=?0;?it?!=?ite;?++it)
- ????????????{
- ????????????????i++;
- ????????????}
- ????????????end?=?current_usec();
- ????????????unordered_map_traverse_us?=?end?-?start;
- ????????}
- ????}//}}}
-
- ????//?Find test
- ????{//{{{
- ????????string_list::iterator it(slist.begin());
- ????????string_list::iterator ite(slist.end());
-
- ????????//map find
- ????????start?=?current_usec();
- ????????for?(int?i?=?0;?it?!=?ite;?++it,?++i)
- ????????{
- ????????????smap[*it]?=?i;
- ????????}
- ????????end?=?current_usec();
- ????????map_find_us?=?end?-?start;
-
- ????????//hash_map find
- ????????it?=?slist.begin();
- ????????start?=?current_usec();
- ????????for?(int?i?=?0;?it?!=?ite;?++it,?++i)
- ????????{
- ????????????shash_map[*it]?=?i;
- ????????}
- ????????end?=?current_usec();
- ????????hash_map_find_us?=?end?-?start;
-
- ????????//unordered_map find
- ????????it?=?slist.begin();
- ????????start?=?current_usec();
- ????????for?(int?i?=?0;?it?!=?ite;?++it,?++i)
- ????????{
- ????????????shash_map[*it]?=?i;
- ????????}
- ????????end?=?current_usec();
- ????????unordered_map_find_us?=?end?-?start;
- ????}//}}}
-
- ????//?Delete test
- ????{//{{{
- ????????string_list::iterator it(slist.begin());
- ????????string_list::iterator ite(slist.end());
-
- ????????//map delete
- ????????start?=?current_usec();
- ????????for?(int?i?=?0;?it?!=?ite;?++it,?++i)
- ????????{
- ????????????smap.erase(*it);
- ????????}
- ????????end?=?current_usec();
- ????????map_delete_us?=?end?-?start;
-
- ????????//hash_map delete
- ????????it?=?slist.begin();
- ????????start?=?current_usec();
- ????????for?(int?i?=?0;?it?!=?ite;?++it,?++i)
- ????????{
- ????????????shash_map.erase(*it);
- ????????}
- ????????end?=?current_usec();
- ????????hash_map_delete_us?=?end?-?start;
-
- ????????//unordered_map delete
- ????????it?=?slist.begin();
- ????????start?=?current_usec();
- ????????for?(int?i?=?0;?it?!=?ite;?++it,?++i)
- ????????{
- ????????????shash_map.erase(*it);
- ????????}
- ????????end?=?current_usec();
- ????????unordered_map_delete_us?=?end?-?start;
- ????}//}}}
-
- ????//stat output
- ????std::cout?<<?" insert, count "?<<?count?<<?std::endl;
- ????std::cout?<<?" std::map "?<<?map_insert_us?<<?" us\n";
- ????std::cout?<<?" std::ext/hash_map "?<<?hash_map_insert_us?<<?" us\n";
- ????std::cout?<<?"std::tr1::unordered_map "?<<?unordered_map_insert_us?<<?" us\n";
-
- ????std::cout?<<?"\n";
- ????std::cout?<<?" traverse, count "?<<?count?<<?std::endl;
- ????std::cout?<<?" std::map "?<<?map_traverse_us?<<?" us\n";
- ????std::cout?<<?" std::ext/hash_map "?<<?hash_map_traverse_us?<<?" us\n";
- ????std::cout?<<?"std::tr1::unordered_map "?<<?unordered_map_traverse_us?<<?" us\n";
-
- ????std::cout?<<?"\n";
- ????std::cout?<<?" find, count "?<<?count?<<?std::endl;
- ????std::cout?<<?" std::map "?<<?map_find_us?<<?" us\n";
- ????std::cout?<<?" std::ext/hash_map "?<<?hash_map_find_us?<<?" us\n";
- ????std::cout?<<?"std::tr1::unordered_map "?<<?unordered_map_find_us?<<?" us\n";
-
- ????std::cout?<<?"\n";
- ????std::cout?<<?" delete, count "?<<?count?<<?std::endl;
- ????std::cout?<<?" std::map "?<<?map_delete_us?<<?" us\n";
- ????std::cout?<<?" std::ext/hash_map "?<<?hash_map_delete_us?<<?" us\n";
- ????std::cout?<<?"std::tr1::unordered_map "?<<?unordered_map_delete_us?<<?" us\n";
-
- ?????
- ????return 0;
- }
-
- void fill_list(string_list&?slist,?size_t count)
- {
- ????for?(size_t i?=?0;?i?<?count;?++i)
- ????{
- ????????std::ostringstream oss;
- ????????oss?<<?i;
- ????????//slist.push_back(MD5::getHexMD5(oss.str().c_str(),?oss.str().length()));
- ????????slist.push_back(oss.str());
- ????}
- }
-
-
- uint64_t current_usec()
- {
- ????struct timeval tv;
- ????gettimeofday(?&tv,?NULL?);
- ????return tv.tv_sec?*?1000?*?1000?+?tv.tv_usec;
- }