使用unordered_map提升查找效率

 

在对网络数据包流(Flow)进行处理的时候,一开始为了简单使用了vector做为Flow信息的存储容器,当其中的元素达到几十万时,程序的执行速度让人无法忍受。已经对vector进行过合理的预先reserve,因为不是push_back的问题,而是查找。后改为unordered_map,对于同样的数据,执行时间从3分40秒提高到10秒。

unordered_map应该是一个C++11特性,较旧的编译器应该不支持。而VC++2012文档中也提到废弃了hash_map,而使用unordered_map。相关参考见http://www.cplusplus.com/reference/unordered_map/unordered_map

 

以下是代码。

先编写键结构,这里用的是俗称的“五元组”:

struct flow_key
{
    int32   ipa;
    int32   ipb;
    uint16  porta;
    uint16  portb;
    uint32  proto;

    friend bool operator== (const flow_key& a, const flow_key& b);
};

 

  因为flow_key是自定义的键类型,因此除了上面的operator==,还需要实现hash函数,这里我是随便写的一个,发生冲突的机会应该相当高了,呵呵。据资料说,当hash函数结果相同时,则继续调用operator==进行比较:

struct flow_hash
{
    size_t operator() (const flow_key& k) const
    {
        return k.ipa + k.ipb + k.porta + k.portb;
    }
};

  接下来编写value结构,我用的是flow_info,代码较多,就不贴了。

为了之后减小代码敲入字数,我给以上述2者为key和value的unordered_map起了个别名:

typedef std::unordered_map<flow_key,  flow_info,  flow_hash>        flow_map_t;

我这里都用的值类型,没用指针类型,也许能再快些,但指针带来的烦恼也是有代价的,呵呵。

在使用此类型的地方,做如下声明:

flow_map_t  m_flows;

OK了,可以用了。

在使用的过程中,如果要查找,代码大概如下:

        pair<flow_map_t::iterator, bool> hash_ret;
        flow_map_t::iterator it = m_flows.find(fkey);

        if(it == m_flows.end())
        {
            // 没找到,插入新项
            hash_ret = m_flows.insert(make_pair(fkey, flow));
            it = hash_ret.first;
        }

注意insert操作的返回类型哦,是一个pair,first是插入的对应的迭代器,second是bool值,指示插入是否成功。

我这里主要是还要进行一些额外操作,所以用了什么find之类,如果你不关心这个键是否已在map之中,只想没有就插入,那直接进行insert操作就可以了,如果已经存在此键,则hash_ret的first就是已存在键的元素所对应的迭代器。

由于我需要以整数下标对流信息进行各种操作,所以我在得到完整的unordered_map之后,把它复制给了vector。

 

posted @ 2013-06-26 23:54  赵子清  阅读(9328)  评论(0编辑  收藏  举报