by zieckey
測試條件:
gcc version 4.2.1 20070719 [FreeBSD]
FreeBSD 7.2-RELEASE #0: Fri May 1 07:18:07 UTC 2009
[email protected]:/usr/obj/usr/src/sys/GENERIC amd64
Intel(R) Xeon(R) CPU E5620 @ 2.40GHz 16核
測試程序說明:
先準備好n個字符串隨機的MD5字符串做爲key,然後分別對3個容器進行插入、遍歷、查找、刪除操作。
例如,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相關的代碼以確保其他人能比較方便的直接拿去編譯運行。
如有錯誤還請跟帖指出,非常感謝。
-
#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;
-
}