Delphi: 如何组织源代码以提高编译器性能?

33

我正在处理一个用Delphi 6编写的大型项目,它有相当多的依赖项,编译整个项目需要几分钟时间。在进行一些更改后重新编译可能会更加耗时,因此最快的方法是终止Delphi,删除所有dcu文件并重新编译。

有没有人知道如何确定编译器变得越来越慢的原因?有什么建议可以组织代码以提高编译性能吗?

我已经尝试了以下几件事情:

  • 显式包含dpr中的大多数单元,而不是依靠搜索路径:没有改善任何东西。
  • 使用命令行编译器dcc32:速度并没有更快。
  • 尝试查看编译器的操作(使用SysInternals的ProcessExplorer):显然它大部分时间运行一个名为'KibitzGetOverloads'的函数。但我对这个信息无能为力...

编辑,目前为止的答案总结:

对于我的情况,最有效的答案是:

  • CnPack中的“清理未使用的单元引用”功能。它自动清除了1000多个引用,使“冷”编译(在编译之前删除所有dcu文件)大约快了两倍。 "冷"编译=在编译之前删除所有dcu文件。它从编译器获取参考列表。因此,如果有一些{$IFDEF}检查,请确保您的所有配置仍然可以编译。

我想尝试的下一件事:

  • 手动重构单元引用(可能使用抽象类),但这需要更多的工作,因为我首先需要确定问题所在。一些可能有用的工具如下:
    • GExperts将项目依赖项浏览器添加到Delphi IDE中(但是不幸的是它不能显示每个分支的大小)
  • Delphi Unit Dependency Viewer V1.0 可以做与 Delphi 相似的事情,但不需要 Delphi。它可以计算一些简单的统计数据(哪些单元被引用最多,...)
  • Icarus 在其中一个答案的链接中被提到。
  • 在我的情况下没有改变任何事情的内容:

    • 将程序和所有组件的所有文件放在一个没有子文件夹的文件夹中。
    • 对磁盘进行碎片整理(我尝试了使用 ramdisk)
    • 为源代码和输出文件夹使用 ramdisk。
    • 关闭实时扫描防病毒软件
    • 在 DPR 文件中列出所有单元,而不是依赖搜索路径。
    • 使用命令行编译器 dcc32 或 ecc32。

    在我的情况下无法应用的内容:

    • 避免在网络共享上有依赖项。
    • 使用 DelphiSpeedUp,因为我已经使用了它。
    • 将所有 DCU 放在一个文件夹中(我总是这样做)

    我没有尝试的内容:

    • 升级到另一个 Delphi 版本。
    • 使用 dcc32speed.exe
    • 使用固态硬盘(我没有尝试过,但我尝试了使用 ramdisk 将所有源代码放在其中。但也许我应该在 ramdisk 上安装 delphi)

    1
    关于您的$IFDEF问题,您应该使用适当的$IFDEF将所使用的单元本身包含起来,以减轻CnPack将它们作为未使用而删除的问题。 - Lieven Keersmaekers
    @Lieven:在合适的$IFDEF内部封装整个单元确实是个好主意。但并不总是可行的:如果该单元属于你不想修改的库的一部分,那么你只能把$IFDEF放在“Uses”中。 - Name
    14个回答

    11

    可能会减慢编译器速度的一些因素

    • 使用冗余的单元 在你的uses子句中。参见这个问题以获取CnPack链接。
    • 没有将单元明确添加到项目文件中。你似乎已经涵盖了这一点。
    • 更改了编译器设置,尤其是包含TDD32信息

    尝试消除在你的uses子句中未使用的单元,并查看是否有所不同。


    1
    谢谢你的回答。cnpack看起来很有趣,我会试一下。TDD32已经被停用了。顺便说一句,还有一个名为ecc32的编译器(调用dcc32),我不知道具体的区别。 - Name
    1
    @Name,我不知道,对于编辑感到抱歉。现在你提到了它,还有dcc32speed.exe。它是由Andreas Hausladen编写的,修补了几个函数以加速编译器。 - Lieven Keersmaekers
    1
    “Clean unused units references” 函数是 cnpack 中一个非常好的解决方案。它几乎可以自动清理超过 1000 个引用,使“冷”编译速度提高了约两倍。 - Name
    包含 TDD32 信息。嗨,这会如何提高编译器速度? - Gabriel
    @ServerOverflow 我回答了可能会减慢编译器速度的内容 ;) - Lieven Keersmaekers

    9
    使用 Delphi 7 和 2009,上周我编译我的应用程序几乎需要2分钟,再加上按下 F9 键并获取主窗体的另外45秒。这件事已经让我疯狂了6个月,而我尝试的一切似乎都不起作用。使用 SysInternals 的 Filemon,我意识到编译器需要的每个单元(主要是组件)都在搜索路径中的每个文件夹中进行搜索,是的,这会产生大量的 FileOpen、FileExists 和 FileNotFound 等操作。我所做的是将组件的所有 DCU、DFM、RES 等放在一个单独的文件夹中,并只将此文件夹和项目所需的其他几个文件夹放在搜索路径中,结果非常惊人。修复之前的另一个问题是调试。在调试时,每次按下 F7、F8 键需要近40秒,这也已经得到了解决。希望这些信息能对您有所帮助。来自委内瑞拉玛格丽塔岛的问候。如果有任何错误,请原谅我的英语。

    不是非常实用,但或许值得一试。 - Name

    8

    请检查搜索路径中是否存在未在本地计算机上的路径。

    例如,不要链接到网络共享上的二进制文件,并检查搜索路径是否检查任何网络共享。


    4

    我没有看到编译器随着时间变慢,但自从我们使用Delphi 6以来已经过了很长时间。

    1. 在Delphi社区中,普遍认为如果你不想升级到最新版本(Delphi 2007或2009),那么Delphi 7是最好/最快/最稳定的版本。您可以考虑升级。
    2. KibitzGetOverloads听起来像是Kibitz编译器中的某个东西——“后台”编译器会提供代码完成、后台错误突出显示、代码工具提示等功能。看起来你最好检查命令行编译器的调用堆栈,而不是IDE;这样你会得到更有用的信息。
    3. 我从未发现删除DCUs后编译速度更快。DCUs的存在是为了使构建增量化,因此更快。如果您在删除所有DCUs后看到编译速度更快,请检查您的硬件。您最近是否进行了磁盘碎片整理?您的驱动器上还有多少可用空间?

    对于命令行编译器,它似乎在执行 KibitzGetOverloads 时花费了大量时间。磁盘空间不是问题,碎片整理可能无法帮助,因为当我将整个源代码放在 RAM 磁盘上时,结果相同。升级到更新的 Delphi 可能是一种选择,但我更愿意找出是什么使 Delphi 变慢。 - Name

    4
    1. 您是否设置了一个单独的文件夹来获取DCUs。如果没有,它们将分散在各处。
    2. 将所有单元及其隐式调用的单元(除库路径中安装的组件)放入dpr中。为确保您没有漏掉一些内容,请清空搜索路径,然后进行编译。
    3. 缩小搜索路径后,您可以尝试通过将组件安装到较少的文件夹中来减少库路径。

    我按照系统进行第一项,但这可能是对那些没有执行此操作的人的一个好提示。如我在原帖中所述,我已经尝试过第二项。我不知道第三项是否有帮助,但应用起来需要相当多的工作,所以这可能是我会尝试的最后一件事情。 - Name

    3

    虽然与你的问题只有部分相关,但我听说使用固态硬盘可以大大减少Delphi编译时间 - Nick Hodges在几周前的Delphi播客中自己也这样说过。 Brian


    有趣的想法,给了我另一个想法:我尝试将整个源代码放在ramdisk上。但是我没有得到任何改进。Windows可能已经缓存了文件。 - Name

    2

    我不知道在大多数情况下应该在哪里划分代码源以提高编译时间,因为我不知道是什么使编译器变慢。因此,直到我真正获得好的结果之前可能需要很长时间。感谢有关防病毒软件的提示。我之前没有想过这个问题,值得一试。 - Name
    1
    第三点可以通过AV允许路径例外来缓解,这样您就可以在那里列出<BDS>\Lib; <project>\dcu; <components>等。 这样编译时间就不会很长了。我知道avast!在家庭版中有此选项。不知道其他的。 - Fabricio Araujo

    2
    我们遇到了相同(或类似)的问题。我们的一个软件包编译时间约为12分钟。经过更改,现在我们已经降至32秒。
    经过多次测试,我们发现“有问题的情况”如下: 在一个单一的软件包中:
    - A模块使用了大量的单元:U1、U2、U3、U4......U100(接口的使用),这是一个重要的单元,集中了所有的初始化工作。 - 软件包的所有单元,U1、U2、U3......U100都使用了A模块(实现的使用)。
    这种“循环引用”不会导致编译错误,因为USES是不同的,但却导致了很长的编译时间。
    解决方案: 消除对每个单元(U1、U2、U3......U100)在A模块中的引用。
    现在,A模块使用大量的单元:U1、U2......U100,但是单元U1、U2......U100不使用A模块。
    这样更改后,编译时间显著降低。
    如果您遇到类似的情况,可以尝试这个方法。
    抱歉我的英语不好。
    问候。
    Neftalí -Germán Estévez-

    有趣的观察。我想我有这样一个案例。我会试着看一下。 - Name
    另外请参考Fabricio Araujo提供的链接,该链接与此方向相同:http://coding.derkeiler.com/Archive/Delphi/borland.public.delphi.non-technical/2006-05/msg00700.html - Name

    2

    我也曾遇到过这个问题,并且我可以列出两个原因:

    1. 循环引用。之前有位先生提到这点是正确的。有时候,我会发现一些大型项目编译速度很快,而一些小型项目却很慢。直到我重新组织了代码,才获得了更快的编译速度。将代码分成许多小单元很容易构建出一个庞大的单元,但这样做会带来很多不利影响。

    2. 我听过很多次,要在像用户可能使用的慢机器上开发。但这只适用于测试部门。我不能浪费时间在编译、Delphi加载速度、包等方面。我买了一台“游戏”电脑(WOW),配备固态硬盘(如前所述)、12GB内存、超频的“i7”英特尔芯片、三张视频卡(联动),运行Vista64(安装所有部件后,Vista并不差)。设置它真的很麻烦。但现在我不再等待电脑了。纯粹的编译速度和加载速度,加上一台没有过去两年里安装的所有垃圾软件的新鲜机器。我甚至卸载了DelphiSpeedUp。不需要它。我也不需要关闭反病毒软件,因为我曾经这样做过,并且遭受了网络垃圾的惩罚。所以反病毒软件保持开启。简单来说,买一台最好的电脑。你的时间比你花在新电脑上的钱更有价值。


    为什么止步于12 GByte,32 GByte不是更加牛逼吗?开玩笑的,你能否提供一些信息,为什么有人需要这样过度的机器来进行Delphi开发? - mghie
    他问如何提高编译器的速度。自从SLI / Crossfire / 固态硬盘以来,Delphi编译速度有所提高吗?自从什么时候开始,Delphi需要超过2GB的内存? - curious slab
    虚拟机在可用RAM中缓存内容,因此如果RAM充足,则源文件将缓存在RAM中。另外,固态硬盘具有更低的随机访问时间,因此可以更快地找到和读取文件。磁盘是编译时的瓶颈,因此任何能加速磁盘速度的都能缩短编译时间。 - Joeri Sebrechts

    1
    尝试安装一个RAM磁盘并将DCU输出路径设置为指向那里。这样做可以将我在DelphiSpeedUp上使用Delphi 2007的编译时间减少一半以上。

    我已经尝试过了,Brian Frost告诉我固态硬盘似乎可以提高性能。在我的情况下,它没有改变任何东西。也许Windows已经很好地缓存了这些文件。 - Name

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接