我有一个Delphi 2009程序,它可以处理大量数据,并且需要尽可能快地使用,而不是使用太多内存。
您通过显着减少执行时间或内存使用量对您的程序性能影响最大的Delphi代码做了哪些小的简单更改?
感谢大家的所有答案。很多很棒的提示。
为了完整起见,我将发表一些关于我发现的Delphi优化的重要文章。
Before you start optimizing Delphi code在About.com
Speed and Size: Top 10 Tricks也在About.com
高性能德尔福的Code Optimization Fundamentals和Delphi Optimization Guidelines,与Delphi 7有关,但仍然非常相关。
答案 0 :(得分:30)
.BeginUpdate;
.EndUpdate;
)
答案 1 :(得分:22)
使用Delphi分析工具(一些here或here)并发现自己的瓶颈。优化错误的瓶颈是浪费时间。换句话说,如果您在此处应用所有这些建议,但忽略了某些人在某些非常重要的代码中放置 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)
答案 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)
答案 13 :(得分:4)
如果您有一个列表,请使用任何动态数组,甚至是如下记录:
这不需要课程,也不需要释放,访问速度非常快。即使它需要增长,你也可以这样做 - 见下文。如果您需要大量更改大小的灵活性,请仅使用TList
或TStringList
。
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)
但令人遗憾的是,调整和优化会让你的成绩提高10%(这很危险);重新设计可以给你90%。一旦你真正理解了目标,你通常可以用更好的术语重述问题(以及解决方案)。
干杯
答案 27 :(得分:1)
检查所有循环,并寻找短路方法。如果您正在寻找特定的东西并在循环中找到它,那么使用BREAK命令立即保释...没有任何感觉循环通过其余部分。如果您知道自己没有匹配项,请尽快使用CONTINUE。
答案 28 :(得分:0)
考虑硬件问题。如果您确实需要性能,请考虑您的程序和数据库运行的硬盘类型。如果您正在运行数据库,则会有很多变量。 RAID并不总是最好的答案。
答案 29 :(得分:0)
也许可以利用VCL FixPack的Andreas 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,它们可以异步完成。匿名方法的使用也有帮助。