二、    从TList开始分析……

为了写一个更好的性能ISAPI Filter,我需要更快速地从TList中删除部分连续的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; //最后一个结点
  for i:= maxI downto 10 do t1.delete(i);
  //正向删除
  //for i:=10 to t2.count-10-1 do t2.delete(10);
end;

这段代码是初始化一个100000个结点的List,然后删除其中的第10个到倒数第10个。这段代码是逆向的,这样的删除速度比较快。如果换成正向删除(已经注释掉),则速度就慢得非常多了。

这样的删除是正常的算法。用测效率的程序测试:逆向删除算法的耗时是21.66个毫秒,则正向删除的耗时却能达到58099.02个毫秒。速度慢了2680倍!!!

但这样就很快了么?不是!我认为就算是逆向删除的速度也并不是快的。

分析TList这个类的源码,我们可以看到,它是这样写的(我加入了注释):

procedure TList.Delete(Index: Integer);
var
  Temp: Pointer;
begin
if (Index < 0) or (Index >= FCount) then //判定Index值是否超界
Error(@SListIndexError, Index);
  Temp := Items[Index];                        //取待删除结点
  Dec(FCount);                                   //Count减一
if Index < FCount then                       //将待删除结点后的Buffer提前
System.Move(FList^[Index + 1], FList^[Index],(FCount - Index) * 
SizeOf(Pointer)); 
if Temp <> nil then                           //发通告
Notify(Temp, lnDeleted); 
end;

由于在TList类是将全部的结点指针存放在FList这个动态数组的指针中,所以只需要将Index+1之后的内存块向前移4个字节,即SizeOf(Pointer),即可实现Index结点的删除。

但是,如果使用这样来删除成批连续的(N个)结点,则要实现N次system.move()操作,操作的内存块的大小决定了system.move()操作的耗时,而Index值越小的的结点在FList中越靠前,则system.move()要操作的内存块也就越大。这就是我认为上述成批删除效率不高的原因,也是正向删除比逆向删除的耗时慢了慢了2680倍的原因。

对于成批删除,理想的算法是从index+len结点开始位置,向前移动count-index-len个结点,这样,就能够一次完成全部的结点移动,实现删除操作。这个思路非常好,至少我认为是这样。为此,我实现了下面的代码:

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这个Buffer中,将删除后的剩余结点直接移动到Left这个位置上,从而完成全部的移动操作。

然后,我们再设count := count-len;来使用个数减少,从而完成了成批量的删除。

好的,如果一切正常,算法的速度将大幅度提升!OHHH,美妙的想法!

但是,真的是这样么?我再用效率测试程序来测试了一轮,结果是这样的:

1.    测试数据为10万个结点,则逆向删除算法耗时为20.56毫秒,CutList()函数耗时9.69毫秒;

2.    测试数据为100万个结点,则逆向删除算法耗时为209.13毫秒,CutList()函数耗时98.01毫秒。

速度比逆向算法提高了一倍,而且应该注意到,CutList()的耗时仍然随数据量的增大而等比例的增大!!!而从CutList()函数的实现来看,数据量增大,算法耗时应该只增加极少才对。

要知道,只加快一倍速度的CutList(),并不是我所想要的!!!但为什么CutList()函数得不到更高的性能呢???

Tlist删除技巧的更多相关文章

  1. PDF中的空白页面怎么删除,PDF页面删除技巧

    在Word中想要删除其中一页文档的怎么办?直接打开就可以删除了,那么我们如何删除PDF其中几页呢?下面小编就来告诉大家PDF删除页面跟空白页面的方法.想要删除PDF文档中的页面,可以使用PDF编辑器, ...

  2. vim中选择匹配文本删除技巧

    试举几例如下: 如何只保留匹配内容行而删除其他行? :v/pattern/d :help :v 如何对每行只保留匹配内容而删除这一行中的其它内容 :%s/^.pattern.$/\1/g 删除包含特定 ...

  3. linux中WDCP的日志彻底删除技巧

    apache或nginx都有开关默认日志,一个是正常访问日志,一个是错误的日志,目录在 /www/wdlinux/nginx-1.0.15/logs /www/wdlinux/httpd-2.2.22 ...

  4. u盘使用记录、痕迹删除技巧方法

    在日常生活的使用U盘过程当中,系统会记录下大量U盘的使用记录信息,那么接下来小编就来同大家分享介绍如何删除掉这些使用记录的方法知识. 1. 往系统里面添加环境变量devmgr_shownonprese ...

  5. [Unity3D]场景间切换与数据传递(以及物体删除技巧)

    http://blog.163.com/kingmax_res/blog/static/77282442201031712216508/ 先介绍一些基本函数(具体用法自己查文档):---------- ...

  6. 数独高阶技巧之八——SDC

    在本系列的第四篇“简单异数链”中,向大家介绍了XY-Wing等一系列Wing类技巧,并提到可以用(拐弯的)数组的观念来理解这些结构,经过第六篇ALS的学习之后,大家回过头再去看Wing,应该可以发现相 ...

  7. ubuntu基础知识与技巧

    root用户与超级用户的切换 (1)  sudo -i (2)  sudo su (3)  su root 安装升级 查看软件xxx安装内容 dpkg -L xxx 查找软件库中的软件 apt-cac ...

  8. 红黑树LLRB

    LLRB——红黑树的现代实现 一.本文内容 以一种简明易懂的方式介绍红黑树背后的逻辑实现2-3-4树,以及红黑树的插入.删除操作,重点在2-3-4树与红黑树的对应关系上,并理清红黑树相关操作的来龙去脉 ...

  9. Ubuntu 命令手册

    提示:命令太多,查找的时候请用Shift+F. 目录 • 1. 前言 • 2 安装升级 • 2.1 查看软件 xxx 安装内容 • 2.2 查找软件库中的软件 • 2.3 显示系统安装包的统计信息 • ...

随机推荐

  1. Office 365使用情况调查不完全分析报告

    感谢大家参与了9月13日在Office 365技术群(O萌)中发起的一个关于Office 365使用情况的调查,在一天左右的时间内,我们一共收到了67份反馈,其中绝大部分是在3分钟内提交的. 本次调查 ...

  2. Android核心组件 Activity组件

    1.Activity简介 四大组件之一的Activity组件,在应用中一个Activity可以用来表示一个界面,中文意思也可以理解为"活动",即一个活动开始,代表Activity组 ...

  3. 基于JQuery实现的文本框自动填充功能

    1. 实现的方法 /* * js实现的文本框的自动完成功能 */ function doAutoComplete(textid,dataid,url){ $("#" + texti ...

  4. 读<<领域驱动设计-软件核心复杂性应对之道>>有感

    道可道,非常道. 名可名,非常名. 无名天地之始,有名万物之母. ---老子 关于标题 好久没写东西了,动笔的动机是看完了一本书,想写点总结性的东西,一是为了回顾一下梳理知识点,二是为了日后遗忘时能有 ...

  5. Java中堆内存和栈内存详解2

    Java中堆内存和栈内存详解   Java把内存分成两种,一种叫做栈内存,一种叫做堆内存 在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配.当在一段代码块中定义一个变量时,ja ...

  6. Unity、c#中的拓展方法讲解

    很早以前看过这个东西,但是没有真正的用到过,希望之后会用到上面的方法, 大概的意思是这样的c#中尤其在用Unity的时候,已有的框架提供给我们一些固定的方法,但是有时我们想对这些方法进行修改, 这时我 ...

  7. 看看C# 6.0中那些语法糖都干了些什么(中篇)

    接着上篇继续扯,其实语法糖也不是什么坏事,第一个就是吃不吃随你,第二个就是最好要知道这些糖在底层都做了些什么,不过有一点 叫眼见为实,这样才能安心的使用,一口气上五楼,不费劲. 一:字符串嵌入值 我想 ...

  8. AngularJS HTML DOM& 事件

    AngularJS 为 HTML DOM 元素的属性提供了绑定应用数据的指令. ng-disabled 指令直接绑定应用程序数据到 HTML 的 disabled 属性 <div ng-app= ...

  9. MP3文件ID3信息编辑器代码开源 - 开源研究系列文章

    上次把磁性窗体的源码开源了,这次就开源另一个程序源码:MP3文件ID3信息编辑器.这个源码也比较简单,关键在于获取和写入MP3文件的这个ID3的信息即可. 这个操作信息编辑的就封装在MP3ID3.ba ...

  10. OpenWRT镜像爬虫搭建本地源

    网上的爬虫不能用,还是先表达谢意,不过我比较懒不喜欢重复写别人写的教程,只贴出修改,怎么用自己看教程吧. 我自己改了一版可以正常爬: #!/usr/bin/env python #coding=utf ...