Board logo

Subject: 建议修改一处代码. [Print This Page]

Author: niaoge    Time: 2007-6-13 14:29     Subject: 建议修改一处代码.

1、CnWizUtils.pas内有放多取得OTA 接口的函数,这些函数在短短的10分钟内总共调用有上百万次,经检测存在以下“问题”,
举一个例子:原函数:
function CnOtaGetEditBuffer: IOTAEditBuffer;
var
  iEditorServices: IOTAEditorServices;
begin  
  Result := nil; //:=nil放在上面要占用该函数10-40%的时间,可能是接口取空值与实列取空值处理机制不一样,
  QuerySvcs(BorlandIDEServices, IOTAEditorServices, iEditorServices);
  if iEditorServices <> nil then
    Result := iEditorServices.GetTopBuffer;
end;

建议改成如下表达:
function CnOtaGetEditBuffer: IOTAEditBuffer;
var
  iEditorServices: IOTAEditorServices;
begin  
  QuerySvcs(BorlandIDEServices, IOTAEditorServices, iEditorServices);
  if iEditorServices <> nil then
  begin
    Result := iEditorServices.GetTopBuffer;
    Exit;//取得后直接退出,
  end;
  Result := nil;//没取得时再用:=nil,放在这里,不占用时间
end;
附件是我改好的CnWizUtils.pas
修改后测不出这些函数调用时间

2、还有一处建议,论坛灌水很不方便,刚才加附件(.pas)时,提示不支持该格式,退回来时原来打的字全没了,又得重新输,中招了好多次了,建议改改

3、还有一处 增加应用程序空闲通知,AddApplicationIdleNotifier,参数应为 TIdleEvent而不是TNotifyEvent,
TIdleEvent原型为TIdleEvent = procedure (Sender: TObject; var Done: Boolean) of object; 其中Done默认为True,
现在cw内的几个空闲过程如TCnEditControlWrapper.OnIdle调用很频繁,能否在Done上想想办法,空闲时只调用一次?

[ 本帖最后由 niaoge 于 2007-6-13 15:04 编辑 ]

Attachment: CnWizUtils.rar (2007-6-13 14:30, 22.96 K) / Download count 395
http://bbs.cnpack.org/attachment.php?aid=315
Author: Passion    Time: 2007-6-13 16:37

nil放在上面要占用该函数10-40%的时间
这是怎么测出来的?

另外这个赋值为nil的语句的汇编代码能否贴出来看看为啥会消耗这么多的时间,难道用了IntfClear这种内部函数?
(上班没装Delphi故此这么一问)
Author: niaoge    Time: 2007-6-13 17:33



QUOTE:
原帖由 Passion 于 2007-6-13 16:37 发表
nil放在上面要占用该函数10-40%的时间
这是怎么测出来的?

另外这个赋值为nil的语句的汇编代码能否贴出来看看为啥会消耗这么多的时间,难道用了IntfClear这种内部函数?
(上班没装Delphi故此这么一问) ...

用AQTime测的,
我不会用汇编代码

[ 本帖最后由 niaoge 于 2007-6-13 17:36 编辑 ]
Author: Passion    Time: 2007-6-13 22:44

一句 Result := nil; 确实调用了IntfClear
见汇编代码:

Unit1.pas.37: Result := nil;
0044C880 8BC3             mov eax,ebx
0044C882 E8C58BFBFF       call @IntfClear
0044C887 33C0             xor eax,eax
0044C889 5A               pop edx
0044C88A 59               pop ecx
0044C88B 59               pop ecx
0044C88C 648910           mov fs:[eax],edx
0044C88F 689CC84400       push $0044c89c
0044C894 C3               ret
0044C895 E97A6FFBFF       jmp @HandleFinally
0044C89A EBF8             jmp -$08
Unit1.pas.38: end;
Author: Passion    Time: 2007-6-13 23:13

我们参考您的代码改动,对此单元的部分函数进行了一些优化。
不过您有几个优化影响了函数原有的功能,我们没改动。

详情可在CVS上下载过来比较一下。
Author: niaoge    Time: 2007-6-14 09:43

第3个问题有没有办法解决?我试了将AddApplicationIdleNotifier参数类型改成TIdleEvent,
原型为:TIdleEvent = procedure (Sender: TObject; var Done: Boolean) of object;
delphi可能取出Done值为True,如果能在Done做做文章就好了,
下面是简单的调试方法,类似于cndebug,不过比cndebug方便,
安装codesite 4,
将下例单元加到delphi路径下
unit csos;
interface
  uses
    SysUtils,CodeSiteLogging;
  function rc4:TCodeSiteObject;
  var
    Frc4:TCodeSiteObject;
implementation
  function rc4:TCodeSiteObject;
  begin
    if not Assigned(Frc4) then
     Frc4:=TCodeSiteObject.Create(nil);
    Result:=Frc4;
  end;
initialization
finalization
  if Assigned(Frc4) then
    FreeAndNil(Frc4);
end.
在CnEditControlWrapper.pas引用csos
在TCnEditControlWrapper.OnIdle内加一行rc4.sendvariant('Done',Done);你会发现,当delphi空闲时,OnIdle一直重复计算,D2007比D2006更快,不过D2006每秒钟也有好几次,而且每算一次都会调用Result.LineCount := Editor.EditView.Buffer.GetLinesInBuffer,这句话很占用时间;,如果能想到办法,让OnIdle只计算一次就好了,
Author: niaoge    Time: 2007-6-14 11:14

to:Passion (LiuXiao)
我从Cvs上下载了与我修改的比较后,发现确实有一处功能与原功能有出入,我改好了,由于上次采用类似于记事本的工具修改的,没有认真审查,这次全部在delphi内审查,其它修改的代码的功能与原功能一样,建议全部采用最后把result:=nil;以提高性能
原来代码内有一处Bug,我也修改好了,参见附件

Attachment: CnWizUtils.rar (2007-6-14 11:14, 23.02 K) / Download count 418
http://bbs.cnpack.org/attachment.php?aid=316
Author: niaoge    Time: 2007-6-14 14:26

ExecuteOnApplicationIdle 这个过程实际等同于 AddApplicationIdleNotifier
但是在启用后,不知为什么,结束时却没有RemoveApplicationIdleNotifier,
别外ExecuteOnApplicationIdle随着程序的运行应是一直不断地加,故当相应的空闲过程执行结束后应执行,RemoveApplicationIdleNotifier
我自己试着全部加上去的,结果发现在Delphi2006运行和退出速度很快,不知道对不对?
附件是全部修改的代码,供参考,不对之处请指证(文件超过2M,发不出去,我发到周总邮箱)

[ 本帖最后由 niaoge 于 2007-6-14 14:44 编辑 ]
Author: Passion    Time: 2007-6-29 23:12

如果用TIdleEvent = procedure (Sender: TObject; var Done: Boolean) of object;用done来控制idle是否要继续调用的话,不同的过程之间可能就因此互相影响了。

ExecuteOnApplicationIdle 这个过程实际等同于 AddApplicationIdleNotifier
——这句不对吧。后者加到FApplicationIdleNotifiers中保存,前者是放FIdleMethods中,FIdleMethods里头的东西被执行时,是删一个执行一个的。所以ExecuteOnApplicationIdle应该只会把参数中传入的Method执行一次,而无需再手工Delete。




Welcome to CnPack Forum (http://bbs.cnpack.org/) Powered by Discuz! 5.0.0