開發C/C++程序的時候,常常要使用map,將一些數據插入map當中,同時伴隨超時刪除的操做,即一個數據記錄插入map以後,若是隔一段時間沒有被消費掉(從map中刪除),那麼就認爲該數據記錄超時了,並且未來也不會被刪除,將永遠留在map中。對於服務器端開發來講,應用時長期運行,若是任由垃圾記錄存留map中,將會無限撐大map,性能受到影響,也有崩潰的可能。好比在接入系統中,客戶端登陸產生了一個惟一識別碼uuid,接入服務端記錄了該 uuid 與後臺服務的關聯,保存在map中,而後在30分鐘以內客戶端沒有發起請求,接入服務端就認爲該客戶端下線,將刪除map中的該uuid的記錄。試想一下,若是接入服務端不刪除該記錄,那麼下次客戶端登陸產生一個新的uuid,舊uuid將一直殘留,而沒有機會刪除。久而久之將會致使map中殘留大量的無效記錄,因此須要有一個超時刪除的機制,用來保證map的容量不會無限增加。下面介紹一下利用桶定時刪除過時數據的方法,這個方法是我同事告訴個人。(固然在這個例子中,不必定非要使用超時刪除機制,換一套方案能夠解決。)算法
首先準備3個map桶:map1,map2,map3。服務器
假設超時時間是5分鐘。性能
定義一個操做標記operate_flag,用來表示應該對哪個桶進行插入操做,operate_flag初始值設爲1,表示對map1進行操做,取值範圍爲{1,2,3}。ui
定義一個刪除標記delete_flag,用來表示應該刪除哪個桶的數據,delete_flag初始值設爲0,表示不刪除任何map,取值範圍爲{0,1,2,3}。spa
具體作法:線程
1,主線程根據operate_flag決定插入哪一個map;隊列
2,另起一個超時線程,每5分鐘定時作以下操做:事件
a,將operate_flag = operate_flag%3+1,表示每隔5分鐘,主線程會插入下一個map桶;ci
b,刪除delete_flag所標識的map桶中的數據,若是爲0,則不刪除;開發
c,將delete_flag = delete_flag%3+1,更新下一次要刪除的map桶。
按照以上的算法,咱們能夠畫出以下的事件列表
時間軸(第幾分鐘) | 當前操做的map桶 | 當前刪除的map桶 | 下一次須要刪除的map桶 |
0 | map1 | 0 | 0 |
5 | map2 | 0 | map1 |
10 | map3 | map1 | map2 |
15 | map1 | map2 | map3 |
20 | map2 | map3 | map1 |
25 | map3 | map1 | map2 |
0~5分鐘的時間內,主線程對map1進行操做;
5~10分鐘的時間內,主線程對map2進行操做;
10~15分鐘的時間內,先清空map3,主線程對map3進行操做,同時在第10分鐘,清除map1的內容,由於map1的內容至少過了5分鐘,已經超過了超時時間;
15~20分鐘的時間內,先清空map1,主線程對map1進行操做,同時在第15分鐘,清除map2的內容,由於map2的內容至少過了5分鐘,已經超過了超時時間;
20~25分鐘的時間內,先清空map2,主線程對map2進行操做,同時在第20分鐘,清除map3的內容,由於map3的內容至少過了5分鐘,已經超過了超時時間;
25~30分鐘的時間內,先清空map3,主線程對map3進行操做,同時在第25分鐘,清除map1的內容,由於map1的內容至少過了5分鐘,已經超過了超時時間;
經過這樣的操做,就能避免map之間的搶鎖操做,惟一須要鎖的地方就是operate_flag和delete_flag,而這兩個鎖能夠設置爲讀寫鎖,更重要的是僅僅每5分鐘才搶一次,幾乎至關於無鎖。
若是不用map桶刪除的超時機制,最笨的辦法是將全部的數據記錄都加上時間戳,放在一個queue裏面,而後根據隊列頭部的記錄,判斷該記錄是否已被map刪除,若是沒刪除,根據時間戳決定多久以後檢查是否超時,或者定時檢查是否超時。這將會致使map搶鎖時間很長,並且隊列可能也會很大。
若是你們有其餘想法,歡迎在評論區提出。