編寫網絡通訊都要面對一個問題,就是要把很久不存活的死連接清除,如果不這樣做那死連接最終會占用大量內存影響服務運作!在實現過程中一般都會使用ping,pong原理,通過ping,pong來更新連接的時效性,最后通過掃描連接列表來清除掉。雖然這種做法比較簡單,但很難抽取出通用性的封裝,掃描整個列表復雜度也比較高。以下講解如何通過lru算法實現一個通用高效的探測超時連接功能類。
什么是lru
在這里還是要大概介紹一下lru,lru算法的設計原則是:如果一個數據在最近一段時間沒有被訪問到,那么在將來它被訪問的可能性也很小.也就是說,當限定的空間已存滿數據時,應當把最久沒有被訪問到的數據淘汰.當然在這里并不需要使用到自動淘汰機制,只需要把未位到達超時的連接清除即可。
在c#中如何實現lru
c#并不存在這樣的數據結構,不過有一個結構很適合實現lru,這個結構就是linkedlist雙向鏈表,通過以下結構圖就容易理解通過linkedlist實現lru
通過linkedlist的功能我們可以把活越項先移出來,然后再把項移到頭部。在這里需要注意linkedlist的remove方法,它有兩個重載版本,兩個版本的復雜度不一樣。一個是o(n)一個是o(1)所以使用上一定要注意,否則在數據多的情況下效率差別巨大(這些細節都可以通過源代碼來查看)!
代碼實現
前面已經大概講述的原理,接下來要做的就是代碼實現了。第一步需要制訂一個基礎可控測對象規則接口,這樣就可以讓現有的已經實現的功能實現它并可得到相關功能的支持。
1
2
3
4
5
6
7
8
9
10
|
public interface idetector { double activetime { get ; set ; } linkedlistnode<idetector> detectornode { get ; set ; } } |
接口定義了兩個屬性,一個是最近活越時間,另一個就是linkedlistnode<idetector>
這個屬性比交關鍵,通過linkedlistnode<idetector>
可以讓linkedlist在remove時復雜度為o(1).接下來就要針對基于lru算法處理超時制定一個應用規則
1
2
3
4
5
6
7
|
public interface ilrudetector { void update(idetector item); void detection( int timeout); double gettime(); action<ilist<idetector>> timeout { get ; set ; } } |
規則也是比較簡單,update用于更新跟蹤對象,一般在處理接受ping或pong包后進行調用;detection方法是探測超出指定時間的對象,時間當位是毫秒,如果存在有超時的對象則觸發timeout事件;gettime是獲取探測器已經運行的時間單位毫秒!規則定好了那接著要做的事實就是要實現它:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
|
class lrudetector : ilrudetector, idisposable { public lrudetector() { mtimewatch = new system.diagnostics.stopwatch(); mtimewatch.restart(); } private buffers.xspinlock xspinlock = new buffers.xspinlock(); private system.diagnostics.stopwatch mtimewatch; private linkedlist<idetector> mitems = new linkedlist<idetector>(); public action<ilist<idetector>> timeout { get ; set ; } public void detection( int timeout) { double time = gettime(); list<idetector> result = new list<idetector>(); using (xspinlock.enter()) { linkedlistnode<idetector> last = mitems.last; while (last != null && (time - last.value.activetime) > timeout) { mitems.remove(last); result.add(last.value); last.value.detectornode = null ; last = mitems.last; } } if (timeout != null && result.count > 0) timeout(result); } public void update(idetector item) { using (xspinlock.enter()) { if (item.detectornode == null ) item.detectornode = new linkedlistnode<idetector>(item); item.activetime = gettime(); if (item.detectornode.list == mitems) mitems.remove(item.detectornode); mitems.addfirst(item); } } public void dispose() { mitems.clear(); } public double gettime() { return mtimewatch.elapsed.totalmilliseconds; } } |
代碼并不復雜,相信不用過多解釋也能看懂相關操作原理。
測試
既然功能已經實現,接下來就要對代碼進行測試看運行效果。測試代碼比較簡單首先開啟一個timer定時執行detection,另外開一個線程去調用update方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
class program { public class testdetector : idetector { public double activetime { get ; set ; } public string name { get ; set ; } public linkedlistnode<idetector> detectornode { get ; set ; } } static void main( string [] args) { lrudetector lrudetector = new lrudetector(); lrudetector.timeout = (items) => { foreach (testdetector item in items) console.writeline($ "{(item.name)} timeout {lrudetector.gettime() - item.activetime}ms" ); }; system.threading.timer timer = null ; timer = new system.threading.timer(o => { timer.change(-1, -1); lrudetector.detection(5000); timer.change(5000, 5000); }, null , 5000, 5000); system.threading.threadpool.queueuserworkitem(o => { int i = 0; while ( true ) { system.threading.thread.sleep(500); i++; testdetector testdetector = new testdetector(); testdetector.name = "my name is " + i; lrudetector.update(testdetector); } }); console.read(); } } |
運行效果:
以上所述是小編給大家介紹的c#中通過lru實現通用高效的超時連接探測,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對服務器之家網站的支持!
原文鏈接:https://www.cnblogs.com/smark/p/9950802.html