Tlist删除技巧
二、????從TList開始分析……
為了寫一個(gè)更好的性能ISAPI Filter,我需要更快速地從TList中刪除部分連續(xù)的Item。比如這樣的一段代碼:
var p : pChar = 'abcdefgh'; procedure TestDelFromTList; var t1 : TList; ??? i? : integer; ??? maxI : integer; begin ? t1 := tlist.create; ? t1.count := 100000; ? for i:=0 to t1.count-1 do t1[i] := p; ? maxI := t1.count-10-1; //最后一個(gè)結(jié)點(diǎn) ? for i:= maxI downto 10 do t1.delete(i); ? //正向刪除 ? //for i:=10 to t2.count-10-1 do t2.delete(10); end;這段代碼是初始化一個(gè)100000個(gè)結(jié)點(diǎn)的List,然后刪除其中的第10個(gè)到倒數(shù)第10個(gè)。這段代碼是逆向的,這樣的刪除速度比較快。如果換成正向刪除(已經(jīng)注釋掉),則速度就慢得非常多了。
這樣的刪除是正常的算法。用測效率的程序測試:逆向刪除算法的耗時(shí)是21.66個(gè)毫秒,則正向刪除的耗時(shí)卻能達(dá)到58099.02個(gè)毫秒。速度慢了2680倍!!!
但這樣就很快了么?不是!我認(rèn)為就算是逆向刪除的速度也并不是快的。
分析TList這個(gè)類的源碼,我們可以看到,它是這樣寫的(我加入了注釋):
procedure TList.Delete(Index: Integer); var ? Temp: Pointer; begin if (Index < 0) or (Index >= FCount) then //判定Index值是否超界 Error(@SListIndexError, Index); ? Temp := Items[Index];?????????????????????? ?//取待刪除結(jié)點(diǎn) ? Dec(FCount); ??????????????????????????????????//Count減一 if Index < FCount then?????????????????????? //將待刪除結(jié)點(diǎn)后的Buffer提前 System.Move(FList^[Index + 1], FList^[Index],(FCount - Index) * SizeOf(Pointer)); if Temp <> nil then?????????????????????????? //發(fā)通告 Notify(Temp, lnDeleted); end;由于在TList類是將全部的結(jié)點(diǎn)指針存放在FList這個(gè)動(dòng)態(tài)數(shù)組的指針中,所以只需要將Index+1之后的內(nèi)存塊向前移4個(gè)字節(jié),即SizeOf(Pointer),即可實(shí)現(xiàn)Index結(jié)點(diǎn)的刪除。
但是,如果使用這樣來刪除成批連續(xù)的(N個(gè))結(jié)點(diǎn),則要實(shí)現(xiàn)N次system.move()操作,操作的內(nèi)存塊的大小決定了system.move()操作的耗時(shí),而Index值越小的的結(jié)點(diǎn)在FList中越靠前,則system.move()要操作的內(nèi)存塊也就越大。這就是我認(rèn)為上述成批刪除效率不高的原因,也是正向刪除比逆向刪除的耗時(shí)慢了慢了2680倍的原因。
對(duì)于成批刪除,理想的算法是從index+len結(jié)點(diǎn)開始位置,向前移動(dòng)count-index-len個(gè)結(jié)點(diǎn),這樣,就能夠一次完成全部的結(jié)點(diǎn)移動(dòng),實(shí)現(xiàn)刪除操作。這個(gè)思路非常好,至少我認(rèn)為是這樣。為此,我實(shí)現(xiàn)了下面的代碼:
procedure CutList(aList:TList; left,len:integer); begin ? with aList do begin System.Move(List^[left+len], List^[left], (Count-left-len) * SizeOf(Pointer)); ??? count := count-len; ? end; end;這段代碼的功能是在TList.List這個(gè)Buffer中,將刪除后的剩余結(jié)點(diǎn)直接移動(dòng)到Left這個(gè)位置上,從而完成全部的移動(dòng)操作。
然后,我們?cè)僭O(shè)count := count-len;來使用個(gè)數(shù)減少,從而完成了成批量的刪除。
好的,如果一切正常,算法的速度將大幅度提升!OHHH,美妙的想法!
但是,真的是這樣么?我再用效率測試程序來測試了一輪,結(jié)果是這樣的:
1.????測試數(shù)據(jù)為10萬個(gè)結(jié)點(diǎn),則逆向刪除算法耗時(shí)為20.56毫秒,CutList()函數(shù)耗時(shí)9.69毫秒;
2.????測試數(shù)據(jù)為100萬個(gè)結(jié)點(diǎn),則逆向刪除算法耗時(shí)為209.13毫秒,CutList()函數(shù)耗時(shí)98.01毫秒。
速度比逆向算法提高了一倍,而且應(yīng)該注意到,CutList()的耗時(shí)仍然隨數(shù)據(jù)量的增大而等比例的增大!!!而從CutList()函數(shù)的實(shí)現(xiàn)來看,數(shù)據(jù)量增大,算法耗時(shí)應(yīng)該只增加極少才對(duì)。
要知道,只加快一倍速度的CutList(),并不是我所想要的!!!但為什么CutList()函數(shù)得不到更高的性能呢???
轉(zhuǎn)載于:https://www.cnblogs.com/sunday-night/p/6169325.html
總結(jié)
- 上一篇: kvm cobbler无人值守批量安装操
- 下一篇: Django框架Day3------之M