简单的更改为您的Delphi程序带来了最大的改进

时间:2008-12-17 02:00:48

标签: performance delphi memory

我有一个Delphi 2009程序,它可以处理大量数据,并且需要尽可能快地使用,而不是使用太多内存。

您通过显着减少执行时间或内存使用量对您的程序性能影响最大的Delphi代码做了哪些小的简单更改?


感谢大家的所有答案。很多很棒的提示。

为了完整起见,我将发表一些关于我发现的Delphi优化的重要文章。

Before you start optimizing Delphi code在About.com

Speed and Size: Top 10 Tricks也在About.com

高性能德尔福的

Code Optimization FundamentalsDelphi Optimization Guidelines,与Delphi 7有关,但仍然非常相关。

35 个答案:

答案 0 :(得分:30)

.BeginUpdate;

.EndUpdate;

答案 1 :(得分:22)

使用Delphi分析工具(一些herehere)并发现自己的瓶颈。优化错误的瓶颈是浪费时间。换句话说,如果您在此处应用所有这些建议,但忽略了某些人在某些非常重要的代码中放置 sleep(1000)(或类似)的事实是浪费您的时间。 首先修复您的实际瓶颈。

答案 2 :(得分:20)

停止对所有内容使用TStringList。

TStringList 是一种通用数据结构,用于有效存储和处理从简单到复杂类型的所有内容。寻找替代品。我使用Delphi Container and Algorithm Library(DeCAL,以前称为SDL)。朱利安EZDSL也应该是一个很好的选择。

答案 3 :(得分:18)

预先分配列表和数组,而不是在每次迭代时增长它们。

在速度方面,这可能对我产生了最大的影响。

答案 4 :(得分:12)

如果需要在循环中使用Application.processmesssages(或类似),请尝试每隔N次迭代调用它。

同样,如果更新进度条,请不要每次迭代都更新它。相反,每x次迭代将其增加x个单位,或者根据时间或总任务长度的百分比来缩放更新。

答案 5 :(得分:9)

  1. FastMM
  2. FastCode(lib)
  3. 使用高性能数据结构,如哈希表(etc)。很多地方制作一个循环可以更快地为您的数据创建查找哈希表。使用相当多的内存,但肯定是快速的。 (这可能是最重要的一个,但2首先是简单的,只需要很少的努力)

答案 6 :(得分:8)

减少磁盘操作。如果有足够的内存,请将文件完全加载到RAM并在内存中执行所有操作。

答案 7 :(得分:7)

考虑仔细使用线程。如果您现在不使用线程,请考虑添加一对。如果你是,请确保你没有使用太多。如果您在双核或四核计算机上运行(大多数都是如此),那么正确的线程调整非常重要。

您可以查看OmniThread Library by Gabr,但Delphi正在开发许多线程库。您可以轻松实现自己的并行使用匿名类型。

答案 8 :(得分:7)

在您做任何事情之前,请确定缓慢的部分。请勿触摸执行速度足够快的工作代码。

答案 9 :(得分:6)

当我开始使用AsyncCalls将用于冻结UI的单线程应用程序转换为(某种程度的)多线程应用程序时,最大的改进就来了。

尽管AsyncCalls可以做很多事情,但我发现它对于这个非常简单的目的很有用。假设你有一个像这样被阻止的子程序:禁用按钮,执行工作,启用按钮。 您将“Do Work”部分移动到本地函数(称为AsyncDoWork),并添加四行代码:

var  a: IAsyncCall;    
a := LocalAsyncCall(@AsyncDoWork);  
while (NOT a.Finished) do 
  application.ProcessMessages;  
a.Sync;

这对您的影响是在一个单独的线程中运行AsyncDoWork,而您的主线程仍可用于响应UI(如拖动窗口或单击Abort)。当AsyncDoWork完成后,代码将继续。因为我将它移动到本地函数,所有本地变量都可用,代码不需要更改。

这是一种非常有限的“多线程”类型。具体来说,它是双线程。您必须确保Async函数和UI不同时访问相同的VCL组件或数据结构。 (我禁用除停止按钮以外的所有控件。)

我不使用它来编写新程序。这只是一个非常快速的&简单的方法使旧程序更具响应性。

答案 10 :(得分:5)

为字符串和数组智能地使用SetLength()。使用FillChar或ZeroMemory优化初始化。

在堆栈上创建的局部变量(例如记录类型)比堆分配的(对象和New())变量更快。

重用对象而不是Destroy然后创建。但请确保管理代码比内存管理器更快!

答案 11 :(得分:5)

使用tstringlist(或类似代码)时,请设置“sorted:= false”直到需要(如果有的话)。看起来很简单...

答案 12 :(得分:5)

  1. 创建单元测试
  2. 验证测试全部通过
  3. 描述您的应用程序
  4. 重构寻找瓶颈和记忆
  5. 从步骤2开始重复(与之前的过程相比)

答案 13 :(得分:4)

如果您有一个列表,请使用任何动态数组,甚至是如下记录:

这不需要课程,也不需要释放,访问速度非常快。即使它需要增长,你也可以这样做 - 见下文。如果您需要大量更改大小的灵活性,请仅使用TListTStringList

type
  TMyRec = record
    SomeString : string;
    SomeValue : double;
  end;

var
  Data : array of TMyRec;
  I : integer;

..begin
  SetLength( Data, 100 ); // defines the length and CLEARS ALL DATA
  Data[32].SomeString := 'Hello';
  ShowMessage( Data[32] );

  // Grow the list by 1 item.
  I := Length( Data );
  SetLength( Data, I+1 );

..end;

答案 14 :(得分:4)

检查大量使用的循环以进行可以(至少部分地)预先计算或使用查找表处理的计算。 Trig函数是经典之作,但它适用于许多其他函数。

答案 15 :(得分:3)

将程序逻辑与用户界面分离,重构,然后独立地优化最常用,最耗费资源的元素。

答案 16 :(得分:2)

识别记录时,如果可能的话,使用整数进行记录比较。虽然“公司名称”的主键可能看似合乎逻辑,但生成和存储此哈希值所花费的时间将大大缩短整体搜索时间。

答案 17 :(得分:2)

  • 关闭调试

  • 开启优化

  • 删除对该单位的所有引用     你实际上并没有使用

  • 查找内存泄漏

答案 18 :(得分:2)

对于我刚开始使用Delphi时的旧BDE开发,我使用了大量TQuery组件。在我向他解释我正在做什么之后,有人告诉我使用TTable大师级细节,这使得程序运行得更快。

调用DisableControls可以省略不必要的UI更新。

答案 19 :(得分:2)

Use the full FastMM并研究文档和来源,看看是否可以根据您的规格进行调整。

答案 20 :(得分:2)

经过广泛测试后,关闭范围和溢出检查。

答案 21 :(得分:2)

使用大量断言进行调试,然后在发货代码中关闭它们。

答案 22 :(得分:1)

您可以考虑使用运行时包。如果有多个程序运行使用相同的包编写,这可能会减少内存占用量。

答案 23 :(得分:1)

如果使用线程,请设置其处理器关联。如果您还没有使用线程,请考虑使用它们,或者如果您的应用程序执行大量I / O,请查看异步I / O(完成端口)。

答案 24 :(得分:1)

考虑DBMS数据库是否真的是最佳选择。如果您只是读取数据并且从不更改它,那么平坦的固定记录文件可以更快地工作,尤其是如果可以容易地映射数据的路径(即,一个索引)。对固定记录文件进行简单的二进制搜索仍然非常快。

答案 25 :(得分:1)

如果你真的,真的,真的需要重量轻,那么你可以摆脱VCL。看看KOL & MCK。如果您这样做,那么您正在交易减少占地面积的功能。

答案 26 :(得分:1)

  • BeginUpdate ... EndUpdate
  • ShortString vs. String
  • 使用数组而不是TStrings和TList

但令人遗憾的是,调整和优化会让你的成绩提高10%(这很危险);重新设计可以给你90%。一旦你真正理解了目标,你通常可以用更好的术语重述问题(以及解决方案)。

干杯

答案 27 :(得分:1)

检查所有循环,并寻找短路方法。如果您正在寻找特定的东西并在循环中找到它,那么使用BREAK命令立即保释...没有任何感觉循环通过其余部分。如果您知道自己没有匹配项,请尽快使用CONTINUE。

答案 28 :(得分:0)

考虑硬件问题。如果您确实需要性能,请考虑您的程序和数据库运行的硬盘类型。如果您正在运行数据库,则会有很多变量。 RAID并不总是最好的答案。

答案 29 :(得分:0)

也许可以利用VCL FixPackAndreas Hausladen

  

VCL Fix Pack是一个Delphi单元   修复运行时的VCL和RTL错误   修补原始功能。如果   您想要修复所有IDE修补程序包   你的申请这个单位就是你   需要。将单元添加到项目中   (Delphi和C ++ Builder)自动完成   安装可用的补丁   适用于您的Delphi / C ++ Builder版本。

答案 30 :(得分:0)

利用一些the FastCode project代码。它的一部分被整合到VCL / RTL中(就像FastMM一样),但是你可以使用更多的东西!

注意,他们有new site他们也在移动,但似乎有点不活跃。

答案 31 :(得分:0)

如果必须进行字符串比较,请使用优化的STRCOMP或TEXTCOMP函数。为简单起见,请使用优化的SAMESTR和SAMETEXT函数。如果您知道案件总是一样的话,请务必选择SAMESTR / STRCOMP。

答案 32 :(得分:0)

在TQuery执行时,避免使用带有查找字段的TTable。

我的报告在大型数据库中速度极慢。它使用带有一堆查找字段的TTable。我在我的应用程序上挂了一个网络监视器,发现当我遍历这个带有查找字段的TTable时,大量的数据流过这些行。改用TQuery大大减少了流量,并在速度方面产生了巨大的差异。

这个建议实际上只是学习用客户端 - 服务器术语思考。

答案 33 :(得分:0)

运行SysInternals ProcessExplorer和FileMonitor,从操作系统的角度观察应用程序的行为。您会发现诸如意外磁盘和注册表活动之类的惊喜。您可能认为您在一次操作中将设置保存到注册表或.ini文件,您可能正在执行100次写入。您可能会发现数据库写入在您认为正在进行时会进行30次写入。其中一些可以通过事务和缓冲等方式进行调整。但直到你找到麻烦点为止。 当我通过U3认证(SanDisk U3驱动器拥有自己的认证)时,我有一个“觉醒”。我的应用程序的U3版本从来没有赚到多少钱,但是锻炼非常值得。

答案 34 :(得分:0)

如果可能,请避免使用thread.synchronize。这会停止一切并等待VCL线程。我们将大多数同步更改为使用thread.queue,它们可以异步完成。匿名方法的使用也有帮助。