慎用Visual Studio C++默認的hash_map

慎用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下調試服務器代碼的異類。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章