慎用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          STLporthash_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

而由于MShash_map实现没有resize函数,我单独对STLport的实现测试了先使用resize函数的结果如下,大家可以发现如果先使用resize函数,速度可以得到更大的提高。

test_hash_map gettimeofday :1015

test_map gettimeofday :2343

test_hash_map gettimeofday :1031

test_map gettimeofday :2375

 

我对STLporthash_map的实现比较熟悉,应该就是hash因子的数组加List存放数据。而MS Visual Studio的实现我初步浏览了一下,应该也类似,具体原因就说不清了,我也不太想耗费体能找出问题的症结所在,就只看表面现象吧。

所以大家在使用Visual Studio hash_map的时候要当心了,

l          第一,这个hash_map实现不怎么快,

l          第二,微软的实现不地道,,基本可以肯定SGI的实现会是默认的标准,有兴趣可以看看BOOSTunordered_map,未来的hash_map应该就是这个样子。

l          第三,没有resize函数,这样几乎可以肯定,这个实现的大容量时的表现应该很烂。我的同事测试在2005下测试上面的程序,测试数量改为了100万后,他的说法是他最后没有耐心等待结果了。而我用2003的STLport测试结果是10s多完成测试。为什么我敢肯定,建议大家去看看hash_map的实现。

另外inmore看了我的测试结果说好像MS实现的迭代器遍历要快,我测试了一下,发现果真如此,难道微软的工程师昏了头,优化hash_map的迭代器遍历去了,但多少怀疑这和MS实现还是有一定得关系。

Microsoft的自己的编译器,实现的东西居然比别人慢一个数量级,MS的工程师应该羞愧一个。测试限于20032005,没有涉及2008,但我基本也不抱太大希望。当然,我在这儿也不劝你把所有的东西替换为STLport的实现,为啥呢?如果你用的第三方库很多,这个成本过高了。除非你和我一样,是一个在Windows下调试服务器代码的异类。

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐