• 提高Delphi的编译速度(bpl和bcp)


    delphi的编译速度提高(一)

    此博文为原创,转载请注明出处

    作者 :二娃

     

    此博文的内容我曾经回答群内和论坛内的网友提问时回答过,现在写第一部分,第二部分,我再给出一个终极的提高速度的方法

    我用过delphi 7,delphi2005,2006,2007 现在零星地用用2009以及2010,但是无论用哪种版本,其中第三方控件是少不了的,可是随之而来的问题是,每多用一种类型的第三方控件,delphi的编辑和代码提示速度降低一些,到最后,像代码提示(实际上也是编译或者预编译)有时弹出提示内容竟要花去1分钟,急得直让人吐血

    我现在将这种慢的地方例出来:

    1.              编译时,Ctrl+F9或者F9,delphi将所有用到的单元pas编译成dcu中间文件,再将dcu组后成可执行文件(exe,dll,bpl)

    2.              首次代码提示第1种情况后的首次代码提示,将此单元内的直接引用或间接引用到的其它单元统统编译成dcu存于内存或者解析dcu的内容存于内存,当编译再次编辑时,delphi先清除dcu解析缓存,从头再来.

    3.              以上两种的慢慢的地方,主要是解析dcu文件开销,第二次代码提示则不需要,因为缓存内已经有解析好的dcu

    要了解决上面的问题我先延伸出一个解释出来

    bcp文件是bpl文件生成时的付产品,对于执行文件来说是没有什么用的,但是对于delphi作用可是少不得,是不可或缺的。bpl和dcp都是为都可以被delphi调用,但是调用的方式是不一样的。

    bpl文件是执行调用:delphi(包括其它的exe)执行时直接访问bpl的地址,如果地址不存在,就会报错.

    bcp文件是编译调用:delphi在编译时不访问引用的bpl的,访问的信息来自相应的dcp,,同一时期编译出来的dcp文件总是正确地记录相关bpl的地址,供delphi编译时通过.delphi编译执行文件时,不会检查bpl与bcp的版本是否一致,它只管读到bcp,因此不管相应bpl有无直正的地址即使bpl不存,dcp说有什么,在什么位置,delphi就完全相应它,编译通过,假如dcp文件没有相关地址信息,即使相应的bpl有,编译也通不过.

    打个比方,bpl好像一个产品,提供特定的功能,dcp文件就好像bpl的产品说明书,delphi编译时就相当于生产,按说明书生产另一个配套产品(exe,dll,bpl), delphi调用bpl时就像把bpl组装到exe.dll上,由于exe,dll是根据说明书上生产来的,它就认为被组装的bpl一定有相关的结口,此时如果产品接口,型号不对,当然不能组装了

           好了,理解了上面,我们可以这样解释:delphi编译文件时(提示框弹出也是一种编译,前面说过),先要准备说明书,如果说明书没有,就现场制作(解析dcu,如果没有dcu文件,就要从pas文件转换成dcp),慢就慢制作说明书这个过程,假如先把说明书提供给delphi,那么delphi就会再花上一段时间造说明书了,这段时间就会被节省下来,很简单,提供相关单元的bpl的dcp文件给它,那怎么提供呢?

    打开工程:Project->Options->Packages->Build with runtime packages 钩上,

    这样我们在写代码时,或者编译测试时,速度就会大大提高,原来要1分钟时间才弹出提示,现在还不1秒中.快了很多吧?

    等到产品最要终于给用户时,再将Build with runtime packages 钩去掉,再编译一个完整的exe 给用户,这样就可以不带bpl了

       如果不想去掉钩,就要把相应的bpl提示给用户,刚才说到的钩内的框内有很多说明书,但不是每种bpl对于最终用户使用exe都是必需的,我的经验是按我使用的控件,先大体把相应的bpl代到,一起考备到一个干净的机器上,然后运行exe,提示缺哪个再考哪个,

    我倾向于后面一种文法,给相关的bpl,但是又会有一个问题来了,我在

    《Delphi打包bpl暨delphi的编译速度提高(二)》中接着讲
    Delphi打包bpl暨delphi的编译速度提高(二)

    此博文为原创,转载请注明出处

    作者 :二娃

    在(一)种我讲到利用dcp文件提高delphi编译及代码提示速度的方法,最后抛出一个问题.

    什么问题呢?假如我的工程是引用包编译的,那么就必需要提相应的bpl给用户,视程序用到的控件种类而定,从几个到几十个不等,这样就有一个效率的问题,比如只用到一个控件包中的一个控件,那么我也提供这组控件的完整的bpl包,那就显得太浪费,不是吗?毕竟你不是M$,每个产品发布时都要用DVD来,

    exe文件小看起来漂亮,编译也快,也许我是一个完美主意者才这样说的.

    如果你用过skype,在这里我给广大delphi爱好者打打气,skype是delphi写的,卖了43亿$,神吧?佩服吧?但我不喜欢skype编译出来的文件或者打包方式,skype提供给用户的就一个exe(08年时是14M多),我想编译skype的人一定很有恒心,14M呢,每次调试时都要花半天才能编译出来,写代码时,代码提示也是个问题。

    如果有方法把exe内用到的所有控件单元单独打包成一个bpl或少量若干个bpl再加上一个exe文件,那这就太完美了,有没有方法呢?有,把程序本身的引用到单元单独提出来,至于间接引用到的单元可以不用管,单独制作一个bpl(dcp也一样)编译输入到exe存放的目录下,编译这个bpl时,delphi提示此bpl是否要此用到其它的bpl,要千万不要引用,否则就白做了. Project->Options->Packages->Build with runtime packages 钩上,在包内就加上你刚才的bpl名称(不带.后面的),OK了.

    这样只有当我改动第三方代码时,我才要重新编译bpl,否则的话,这块的编译永远省略,速度那提高得没话说.

    我自已制作了一个这样的ide工具,是从cnwizars基础上写的,用于自动查找工程或工程组中引用的单元,再将这些单元制作成bpl,但是由于tree的那部分用到商业控件,所以不能发布,等我有空件时改成免费控件时,再发布给相要的人使用.

    用上面的方法,无论手动或自动制作的bpl,看上去很美,用起来也呱呱叫,但是紧接着问题就来了。那就是多线程的问题。网上有人提问过,我实际中也遇到过,

    线程在bpl文件内使会时不时地出问题,而且出现的问题没有有规律,无法测试跟踪或者太难测试,原因当然不只是vcl控件不是线程安全的这一个原因这样简单。在bpl内,线程的waitfor等线程方法会无限制地等下去.程序也许可以启动,但退不出来,等等,我个人的理解bpl 还不是真正意义上的dll,在dll内Hintance有真正的实例,bpl则不是.所以线程退不出来。线程在地址上读写冲突.比如,loadbpl时,线程就开始工作,可是这时实例还没有创建....

    线程不能在bpl内运行,或者运行不好,那有没有一种方法将线程提到bpl外运行呢.我之前的方法是将含有线程的代码不引用到bpl内,一个个单元区分,甚至改大量地改动第三控件的代码,但是随着使用深入,发现这种方法也太不现实,有时改动的第三方代码太多,再遇到含有线程的控件如果是基类的话,那区分的地方就更多了,经过我多次实验,我终于发现,只要线程的实例的创建不要由bpl内的代码直接创建就行,间接创建就不会有问题,经过多次的实践,最终证实是这样的, 明白了这个,那只需要稍微地改动一个第三方代码,问题就好办多了。下面简单举个例子

    某bpl内单元种有一段创建线程的实例的地方:

    (终极解决方法)

    Unit Unitbpl

    Interface

    Use

    …….

    Implementation

    procedure Createxxxthread;

    begin

    ….

    fxxxthread:= Txxxthread.create(someparams);

    …..

    end;

    end.


    我现在将上面的单元稍微改动成以下

    Unit Unitbpl

    Interface

    Use

    …….

    TCreateThreadFun=Function(Somparms): Txxxthread;

    Var

    _CreateThreadFun: TCreateThreadFun=nil;

    Implementation

    procedure Createxxxthread;

    begin

    ….

    if @_CreateThreadFun<>nil then

    fxxxthread:=_CreateThreadFun(someparams);

    …..

    end;

    end.

     


    接着我再写一个单元

    Unit CreateThreadUnit

    Interface

    Use

    Unitbpl;

    Implementation

    Function newCreateThreadFun(someparams): Txxxthread;

    Begin

    result:=Txxxthread.create(someparams);//线程实例在exe内创建

    End;

    Initialization

    @ CreateThreadFun:= newCreateThreadFun //初始化时,这里填写地址

    Finalization

    @ CreateThreadFun:=nil; //也可以不要这一行

    End.


    //注意此单元直接此用到exe工程中引用了,千万不能放在bpl内,

    以上方法经过千万的试验,线程没有任何问题。

    http://www.vckbase.com/module/articleContent.php?id=4372

  • 相关阅读:
    oracle 用户与表空间关系
    关于数据库主从表、主键PRIMARY KEY 外键约束 FOREIGN KEY 约束----NOT NULL,DEFAULT,CHECK
    数据库中主键与外键
    MySQL性能测试工具sysbench的安装和使用
    Linux VNC server 安装配置
    Linux 用户管理【UID和GID】
    性能测试之稳定性测试
    NoSql Cassandra
    数据库事务处理原理
    思考问题
  • 原文地址:https://www.cnblogs.com/findumars/p/5624891.html
Copyright © 2020-2023  润新知