日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪(fǎng)問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) >

hashmap::begin() 坑

發(fā)布時(shí)間:2025/3/21 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 hashmap::begin() 坑 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

因業(yè)務(wù)需要, 使用stl中的list+hashmap實(shí)現(xiàn)了一個(gè)容器做緩存;支持lru特性、? 支持O(1)時(shí)間的push_back, pop_head, find/delete。


大概實(shí)現(xiàn)是 將hashmap的iterator的關(guān)鍵部分作為list的元素; 將list的iterator的關(guān)鍵部分作為hashmap的value的其中一部分。 hashmap是真正存放數(shù)據(jù)的。

這樣能夠狠容易的從hashmap::iterator中解析得到對(duì)應(yīng)的list::iterator, 也能夠狠容易的從list::iterator解析得到對(duì)應(yīng)的hashmap::iterator。

其中后者代碼如下:

inline typename HashType::iterator LitToHit(typename ListType::iterator &it){//static typename HashType::iterator hit = m_hash.begin();//只是重用其中的_M_ht_List_node<ListKeyType> * lnode = static_cast<_List_node<ListKeyType> *>(it._M_node);hit._M_cur = lnode->_M_data;return hit;}
這個(gè)函數(shù)用的非常頻繁。 測(cè)試中發(fā)現(xiàn)這個(gè)函數(shù)非常影響性能,當(dāng)時(shí)十分不理解, 以為就是很簡(jiǎn)單的O(1)而已。 仔細(xì)看代碼之后才發(fā)現(xiàn)其中玄機(jī)。

hashmap一維是個(gè)指針數(shù)組, 數(shù)組元素指向沖突處理鏈表。begin遍歷該數(shù)組, 返回第一個(gè)指針?lè)强盏臄?shù)組下標(biāo)指向的數(shù)據(jù)節(jié)點(diǎn)。 當(dāng)元素較少時(shí), begin可能會(huì)非常慢、一直遍歷到數(shù)組尾部才能找到第一個(gè)數(shù)據(jù)節(jié)點(diǎn)。

解決方法是使用static變量即可。



代碼如下,以后會(huì)有很多地用到,貼出以做備忘。

#pragma once//queue。 插入時(shí)key唯一。 O(1)的pushback, pophead, find/delete#include <list> #include <ext/hash_map>using namespace std; using namespace __gnu_cxx;template <typename Key, typename Value> class UniqQueue { public:class ValueNode;typedef hash_map<Key, ValueNode> HashType;typedef _Hashtable_node<pair<const Key, ValueNode> > * ListKeyType;typedef list<ListKeyType> ListType;typedef Key KeyType;typedef Value ValueType;typedef UniqQueue ThisType;class ValueNode{public:_List_node<ListKeyType> *list; // lru鏈表中的位置Value value; // 元素ValueNode():list(NULL), value() {}ValueNode(const ValueNode &r):list(r.list), value(r.value){}private:ValueNode &operator=(const ValueNode &r);//disable};private: HashType m_hash;ListType m_list;pthread_mutex_t m_lock;pthread_cond_t m_cond;public:UniqQueue():m_hash(1000000){pthread_cond_init(&m_cond, NULL);pthread_mutex_init(&m_lock, NULL);}~UniqQueue(){pthread_cond_destroy(&m_cond);pthread_mutex_destroy(&m_lock);}pthread_mutex_t & lock(){return m_lock;}void push_back(const Key & k, const Value &content){ pthread_mutex_lock(&m_lock);pair<typename HashType::iterator, bool> it = m_hash.insert(make_pair(k, ValueNode()));it.first->second.value = content;if(it.second == true)//cache中新加的數(shù)據(jù){ typename ListType::iterator lii = m_list.insert(m_list.end(), GetListNode(it.first));SetList(it.first, lii);}else{}pthread_cond_signal(&m_cond);pthread_mutex_unlock(&m_lock);return;}Value peak_head(){Value vn;typename ListType::iterator lii;typename HashType::iterator hit;// pthread_cleanup_push(Cleanup, this);pthread_mutex_lock(&m_lock);while(m_list.size() == 0){pthread_cond_wait(&m_cond, &m_lock);}lii = m_list.begin();hit = LitToHit(lii);//can not define Value vn; here.. because of cond_wait?? vn = hit->second.value;pthread_mutex_unlock(&m_lock);// pthread_cleanup_pop(0);return vn;}Value peak_head_nolock(){Value vn;typename ListType::iterator lii = m_list.begin();typename HashType::iterator hit = LitToHit(lii);vn = hit->second.value;return vn;}Value find(const Key &k){Value v;pthread_mutex_lock(&m_lock);typename HashType::iterator it = m_hash.find(k);if(it == m_hash.end()) ;elsev = it->second.value;pthread_mutex_unlock(&m_lock);return v;}void pop_head(bool want = true){if(want) pthread_mutex_lock(&m_lock);typename ListType::iterator lii = m_list.begin();typename HashType::iterator hit = LitToHit(lii);m_list.erase(lii);m_hash.erase(hit);if(want) pthread_mutex_unlock(&m_lock);}private://lock helperstatic void Cleanup(void *arg){ThisType *tis = (ThisType *)arg;pthread_mutex_unlock(&(tis->m_lock));}private: //iterator tool functionsinline ListKeyType GetListNode(typename HashType::iterator &v){return v._M_cur;}inline typename HashType::iterator LitToHit(typename ListType::iterator &it){static typename HashType::iterator hit = m_hash.begin();//只是重用其中的_M_ht_List_node<ListKeyType> * lnode = static_cast<_List_node<ListKeyType> *>(it._M_node);hit._M_cur = lnode->_M_data;return hit;}inline void SetList(typename HashType::iterator &v, typename ListType::iterator it){v->second.list = static_cast<_List_node<ListKeyType> * >(it._M_node);} };
當(dāng)時(shí)測(cè)試場(chǎng)景:

1寫(xiě)線(xiàn)程從1開(kāi)始遞增key,不停得push_back;? 1讀線(xiàn)程不停的peak_head+pop_head。

異常現(xiàn)象:

1)push_back線(xiàn)程的pthread_mutex_lock獲取鎖操作時(shí)間越來(lái)越長(zhǎng), 從0-1us變?yōu)閹资畟€(gè)ms。

2)peak_head+pop_head非常消耗cpu,幾乎吃滿(mǎn)cpu。 而寫(xiě)線(xiàn)程只占30%左右的cpu。

3)內(nèi)存用完后變得更慢, push_back大概每秒只能push 30個(gè)左右。

4)其他等等

當(dāng)時(shí)百思不得其解,甚至懷疑pthread contidion的效率、 系統(tǒng)環(huán)境有問(wèn)題。

其實(shí)1和2都已經(jīng)明確的指向了同一個(gè)問(wèn)題了。 1獲取鎖慢, 肯定是其他線(xiàn)程持有鎖的時(shí)間長(zhǎng)導(dǎo)致的。 2吃滿(mǎn)cpu,正好說(shuō)明獲取鎖后做大量運(yùn)算需要時(shí)間長(zhǎng)。

就是peadk_head慢。 慢在哪, 仔細(xì)分析就是hashmap::begin慢



總結(jié)

以上是生活随笔為你收集整理的hashmap::begin() 坑的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。