慎用Visual Studio C++默认的hash_map
写了一个模块客户端和服务器共用,为了加快查询速度,用了hash_map,今天一个兄弟老卢测试说将其中的hash_map替换成map后速度更快,有点晕。自己写了一段代码在Windows下用Visual Studio C++测试hashmap。
首先说明,hashmap目前还没有进入C++的规范,但是大部分厂商都实现了这个容器,测试的hashmap有两种:
l Visual Studio 2003自己默认带的hash_map,
l STLport的hash_map
当然用过Visual Studio默认自带的hashmap的兄弟会知道,其和SGI的一脉的STL实现不太一样,包括模板声明方式等都自成一套。所以其实使用的时候还要注意。这儿就不啰嗦这个问题了。同时麻烦大家注意我测试的版本是2003,使用的是DEBUG版本。
测试代码如下,如果你觉得枯燥,可以跳过这段看代码直接看结果,代码其中用了ACE的一些代码测试时间差:
#include <stdio.h>
#include <iostream>
#include <map>
#include <hash_map>
#include <ace/OS.h>
#include <ace/Time_Value.h>
void test_hash_map()
{
ACE_Time_Value tvStart(0);
ACE_Time_Value tvEnd(0);
ACE_Time_Value tvPassTime(0);
tvStart = ACE_OS::gettimeofday();
hash_map<size_t,int> int_hash_map;
//测试10万次
const size_t TEST_NUMBER = 10*10000;
//注意这行代码,VS.NET默认的STL没有这个函数的,而STLPort的实现有这个函数
int_hash_map.resize(TEST_NUMBER);
//顺序插入一组数据
for (size_t i= 0;i<TEST_NUMBER;++i)
{
int_hash_map[i]=0;
}
//查询20万次,一般能查询到,一半不能查询到
for (size_t i= 0;i<2*TEST_NUMBER;++i)
{
int_hash_map.find(i);
}
//得到毫秒的时间差
tvEnd = ACE_OS::gettimeofday();
tvPassTime = tvEnd - tvStart;
cout<<"test_hash_map gettimeofday :"<<tvPassTime.msec()<<" "<<endl;
};
void test_map()
{
ACE_Time_Value tvStart(0);
ACE_Time_Value tvEnd(0);
ACE_Time_Value tvPassTime(0);
tvStart = ACE_OS::gettimeofday();
map<size_t,int> int_map;
//测试10万个数据
const size_t TEST_NUMBER = 10*10000;
for (size_t i= 0;i<TEST_NUMBER;++i)
{
int_map[i]=0;
}
for (size_t i= 0;i<2*TEST_NUMBER;++i)
{
int_map.find(i);
}
//得到毫秒的时间差
tvEnd = ACE_OS::gettimeofday();
tvPassTime = tvEnd - tvStart;
cout<<"test_map gettimeofday :"<<tvPassTime.msec()<<" "<<endl;
};
int main(int argc, char* argv[])
{
for (int j=0;j<10;++j)
{
test_hash_map();
test_map();
}
return 0;
}
使用Visual Studio 默认的STL的测试结果是,比较让人惊讶的是hash_map的速度不比map快多少,(在我一个同事的VS2005的机器上测试,map居然比hash_map快),节约篇幅,只写了2组测试结果。其他测试结果偏差不大。
test_hash_map gettimeofday :3093
test_map gettimeofday :3484
test_hash_map gettimeofday :3250
test_map gettimeofday :3531
而使用STLPort的测试结果如下:hash_map速度比MS的实现快了一倍多,map也比MS的实现快。
test_hash_map gettimeofday :1312
test_map gettimeofday :2359
test_hash_map gettimeofday :1312
test_map gettimeofday :2375
而由于MS的hash_map实现没有resize函数,我单独对STLport的实现测试了先使用resize函数的结果如下,大家可以发现如果先使用resize函数,速度可以得到更大的提高。
test_hash_map gettimeofday :1015
test_map gettimeofday :2343
test_hash_map gettimeofday :1031
test_map gettimeofday :2375
我对STLport的hash_map的实现比较熟悉,应该就是hash因子的数组加List存放数据。而MS Visual Studio的实现我初步浏览了一下,应该也类似,具体原因就说不清了,我也不太想耗费体能找出问题的症结所在,就只看表面现象吧。
所以大家在使用Visual Studio 的hash_map的时候要当心了,
l 第一,这个hash_map实现不怎么快,
l 第二,微软的实现不地道,,基本可以肯定SGI的实现会是默认的标准,有兴趣可以看看BOOST的unordered_map,未来的hash_map应该就是这个样子。
l 第三,没有resize函数,这样几乎可以肯定,这个实现的大容量时的表现应该很烂。我的同事测试在2005下测试上面的程序,测试数量改为了100万后,他的说法是他最后没有耐心等待结果了。而我用2003的STLport测试结果是10s多完成测试。为什么我敢肯定,建议大家去看看hash_map的实现。
另外inmore看了我的测试结果说好像MS实现的迭代器遍历要快,我测试了一下,发现果真如此,难道微软的工程师昏了头,优化hash_map的迭代器遍历去了,但多少怀疑这和MS实现还是有一定得关系。
Microsoft的自己的编译器,实现的东西居然比别人慢一个数量级,MS的工程师应该羞愧一个。测试限于2003和2005,没有涉及2008,但我基本也不抱太大希望。当然,我在这儿也不劝你把所有的东西替换为STLport的实现,为啥呢?如果你用的第三方库很多,这个成本过高了。除非你和我一样,是一个在Windows下调试服务器代码的异类。