map 与 hash_map 性能比较

由于工作需要,最近不得不关注 map 与 hash_map 的性能,于是花了两天的功夫验证了一下,下面把验证的结果贴出来,给大家看看,希望对大家有帮助。


我主要对 map 和 hash_map 的插入、查询、遍历、清除(也就是清空)作了对比。


先来看一下我的源程序(可以直接在Windows下编译):

#include <stdio.h>
#include <hash_map>
#include <map>
#include <time.h>
#include <iostream>
#include <Windows.h>
#include <stdlib.h>
#include <winternl.h>

using namespace std;

#define PACKETS_COUNT 2000000

// Struct of response packet
typedef struct _PACKET_RESPONSE_
{
    int packetNum;                  // The num of current packet
    int count404;                   // The count of 404 Not Found
    clock_t clockTick;              // The clock tick of the packet that start at the process opened
}PACKET_RESPONSE;

typedef map<unsigned int, _PACKET_RESPONSE_*> RESPONSE_HASH_MAP;

PACKET_RESPONSE **response = {NULL};

// 插入
int insert(RESPONSE_HASH_MAP &responseHashMap)
{
	for (int i=0; i<PACKETS_COUNT; i++)
	{
		PACKET_RESPONSE *newPacketResponse = *(response+i);
        newPacketResponse->count404  = i;
		newPacketResponse->packetNum = i;
		newPacketResponse->clockTick = clock();

		responseHashMap.insert(RESPONSE_HASH_MAP::value_type(i, newPacketResponse));
	}

	cout << "OK!" << endl;
	return 0;
}

// 查找
int find(RESPONSE_HASH_MAP::iterator &iter, RESPONSE_HASH_MAP *responseHashMap, int key)
{
	iter = responseHashMap->find(key);
    if (responseHashMap->end() == iter)
    {
		cout << "not find!" << endl;
        return -1;
    }

	cout << "find OK !\nKey: " << key << "\ncount404: " <<  iter->second->count404 << "\npacketNum: " << iter->second->packetNum << "\nclockTick: " << iter->second->clockTick << endl;
}

// 遍历
int visit(RESPONSE_HASH_MAP &responseHashMap)
{
	int MaxPacketNum = 0;
	RESPONSE_HASH_MAP::iterator iter = responseHashMap.begin();
	while (responseHashMap.end() != iter)
	{
		if (MaxPacketNum < iter->second->packetNum)
		{
			MaxPacketNum = iter->second->packetNum;
		}
		++iter;
	}
	cout << "MaxPacketNum is: " << MaxPacketNum << endl;
	return 0;
}

// 清理
int clear(RESPONSE_HASH_MAP &responseHashMap)
{
	if (0 != responseHashMap.size())
	{
		responseHashMap.clear();
	}

	return 0;
}

DWORD getCpuUsage()
{  

    MEMORYSTATUS ms;
    ::GlobalMemoryStatus(&ms);

    return ms.dwMemoryLoad;
} 

int main()
{
	response = new PACKET_RESPONSE*[PACKETS_COUNT];
	clock_t t = clock();
	for (int i=0; i<PACKETS_COUNT; i++)
	{
		response[i] = new PACKET_RESPONSE;
	}
	cout << "======================> clock is:" << clock()-t << endl;

	RESPONSE_HASH_MAP responseHashMap;
	RESPONSE_HASH_MAP::iterator iter = responseHashMap.begin();
	DWORD dwStart = getCpuUsage();

	clock_t start = clock();
	insert(responseHashMap);
	cout << "====> insert clock is: " <<  clock()-start << " ms" << endl;
	DWORD dwInsert = getCpuUsage();
	cout << "insert 内存使用率为: " << dwInsert-dwStart << "%" << endl;

	RESPONSE_HASH_MAP::iterator it = responseHashMap.begin();
	clock_t eraseStart = clock();
	for (int i=0; i<1000; i++)
	{
		PACKET_RESPONSE *newNode = new PACKET_RESPONSE;
		newNode->packetNum = PACKETS_COUNT + i;
		newNode->count404  = PACKETS_COUNT + i;
		newNode->clockTick = clock();
		responseHashMap.insert(RESPONSE_HASH_MAP::value_type(PACKETS_COUNT + i, newNode));

		it = responseHashMap.erase(it);
	}
	cout << "=====> erase clock is: " << clock()-eraseStart << " ms" << endl;
	clock_t findStart = clock();
	find(iter, &responseHashMap, PACKETS_COUNT-1);
	cout << "====> find clock is: " << clock()-findStart << " ms" << endl;
	DWORD dwFind = getCpuUsage();
        cout << "find 内存使用率为: " << dwFind - dwInsert << "%" << endl;

	clock_t visitStart = clock();
	visit(responseHashMap);
	cout << "====> visit clock is: " << clock()-visitStart << " ms" << endl;
	DWORD dwVisit = getCpuUsage();
	cout << "visit 内存使用率为:" << dwVisit << "%" << endl;

	clock_t clearStart = clock();
	clear(responseHashMap);
	cout << "======> clear clock is: " << clock()-clearStart << " ms" << endl;
	DWORD dwClear = getCpuUsage();
	cout << "clear 内存使用率为:" << dwClear << "%" << endl;

	return 0;
}


    由于我是验证 map 与 hash_map 的性能,所以有些变量的命名是按照之前 hash_map 来命名的,不要觉得奇怪。


我把验证的结果贴出来。


<usigned int, PACKET_RESPONSE*>                  -- 自己管理内存。
插入 查询遍历
200条 4ms 2ms 1ms hash_map
            2ms2ms 1msmap


2000条 33ms 3ms 3ms hash_map
17ms 2ms3ms map


20000条 400ms 2ms 21ms hash_map
178ms 2ms27ms map


200000条 10s 3ms 185ms hash_map
2s 3ms250ms map


2000000条 8min 3ms 1.8s hash_map
22s 4ms2.6s map



<usigned int, PACKET_RESPONSE>-- 把内存交给 map 或者 hash_map
插入 查询遍历
200条 6ms 2ms 1ms hash_map
            2ms2ms 1msmap


2000条 33ms 3ms 3ms hash_map
17ms 2ms3ms map


20000条 400ms 3ms 21ms hash_map
178ms 2ms27ms map


200000条 10s 3ms 185ms hash_map
2s 3ms250ms map


2000000条 9min 3ms 1.7s hash_map
22s 3ms2.5s map




<usigned int, int> -- value 类型为内置类型
插入 查询遍历
200条 6ms 1ms 1ms hash_map
2ms 2ms1ms map


2000条 34ms 1ms 3ms hash_map
17ms 1ms3ms map


20000条 400ms 1ms 22ms hash_map
175ms 2ms27ms map


200000条 10s1ms 186mshash_map
2s 1ms249ms map


2000000条 9min 1ms 1.8s hash_map
22s 2ms2.5s map




<usigned int, PACKET_RESPONSE*>                --自己管理内存    批量申请内存
插入 查询遍历 清除
200条 4ms 2ms 1ms 1ms hash_map
2ms 2ms1ms 0msmap


2000条 31ms 2ms 3ms 34ms hash_map
15ms 3ms4ms 1msmap


20000条 400ms 3ms 21ms 1.3s hash_map
186ms 3ms35ms 10msmap


200000条 10s2ms 183ms74s hash_map
2.1s 4ms288ms 110msmap


2000000条 8min 2ms 1.7s 1h hash_map
22s 3ms2.5s 900msmap


我是根据 value 的类型不同而作的验证。从结果中可以看出,map 的插入、清除性能远比 hash_map 的要高,尤其是清除,大家看最后一个,清除 200W 条的记录时,map 只花了900ms,而 hash_map 却花了一个小时,我开始还以为程序有问题,后来我花了几个小时验证了好几遍,都是这样。而 hash_map 的遍历性能比 map 要高。如果你使用的时候频繁插入或者频繁清除的话,就选择 map,如果你频繁的遍历那就建议使用 hash_map。还有,这个跟 value 的类型没多少关系,我开始在网上看有些人说 map 对内置类型的处理性能比 hash_map 高,而对于自定义类型的处理 hash_map 要高,事实证明,不是这样的。


后来我怀疑是 new 操作影响了性能,所以我用了一个批量申请内存,但是从验证的结果来看,这个对性能没多大的影响。如果你要自己管理内存的话,我建议还是批量申请内存好。如果你不想自己管理内存,那就把内存管理交给 map 或者 hash_map,它们有着一套非常不错的内存管理机制,当它们释放完内存后,并不是交给 ISO,而是留着自己下次使用。这个就是我上面<usigned int, PACKET_RESPONSE>所列出的情况,是将自定义的结构体直接插入 map 或 hash_map中。


我上面的代码是使用了批量申请内存,然后自己管理内存的。如果大家想看看其它的情况的话,可以自己改下代码。


希望对大家有所帮助,还有如果有人觉得哪里不对的话可以告诉我,大家共同进步。



博主所有文章已转自私人博客Joe 的个人博客,谢谢关注!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值