在對網絡數據包流(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。