Tutorial :What Simple Changes Made the Biggest Improvements to Your Delphi Programs [closed]



Question:

I have a Delphi 2009 program that handles a lot of data and needs to be as fast as possible and not use too much memory.

What small simple changes have you made to your Delphi code that had the biggest impact on the performance of your program by noticeably reducing execution time or memory use?


Thanks everyone for all your answers. Many great tips.

For completeness, I'll post a few important articles on Delphi optimization that I found.

Before you start optimizing Delphi code at About.com

Speed and Size: Top 10 Tricks also at About.com

Code Optimization Fundamentals and Delphi Optimization Guidelines at High Performance Delphi, relating to Delphi 7 but still very pertinent.


Solution:1

The biggest improvement came when I started using AsyncCalls to convert single-threaded applications that used to freeze up the UI, into (sort of) multi-threaded apps.

Although AsyncCalls can do a lot more, I've found it useful for this very simple purpose. Let's say you have a subroutine blocked like this: Disable Button, Do Work, Enable Button. You move the 'Do Work' part to a local function (call it AsyncDoWork), and add four lines of code:

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

What this does for you is run AsyncDoWork in a separate thread, while your main thread remains available to respond to the UI (like dragging the window or clicking Abort.) When AsyncDoWork is finished the code continues. Because I moved it to a local function, all local vars are available, an the code does not need to be changed.

This is a very limited type of 'multi-threading'. Specifically, it's dual threading. You must ensure that your Async function and the UI do not both access the same VCL components or data structures. (I disable all controls except the stop button.)

I don't use this to write new programs. It's just a really quick & easy way to make old programs more responsive.


Solution:2

.BeginUpdate;

.EndUpdate;

;)


Solution:3

Use a Delphi Profiling tool (Some here or here) and discover your own bottle necks. Optimizing the wrong bottlenecks is a waste of time. In other words, if you apply all of these suggestions here, but ignore the fact someone put a sleep(1000) (or similar) in some very important code is a waste of your time. Fix your actual bottlenecks first.


Solution:4

Stop using TStringList for everything.

TStringList is not a general purpose datastructure for effective storage and handling of everything from simple to complex types. Look for alternatives. I use Delphi Container and Algorithm Library (DeCAL, formerly known as SDL). Julians EZDSL should also be a good alternative.


Solution:5

Pre-allocating lists and arrays, rather than growing them with each iteration.

This has probably had the biggest impact for me in terms of speed.


Solution:6

If you need to use Application.processmesssages (or similar) in a loop, try calling it only every Nth iteration.

Similarly, if updating a progressbar, don't update it every iteration. Instead, increment it by x units every x iterations, or scale the updates according to time or as a percentage of overall task length.


Solution:7

  1. FastMM
  2. FastCode (lib)
  3. Use high performance data structures, like hash table (etc). Many places it is faster to make one loop which makes lookup hash table for your data. Uses quite lot of memory but it surely is fast. (this maybe is most important one, but 2 first are dead simple and need very little of effort to do)


Solution:8

Reduce disk operations. If there's enough memory, load the file entirely to RAM and do all operations in memory.


Solution:9

Consider the careful use of threads. If you are not using threads now, then consider adding a couple. If you are, make sure you are not using too many. If you are running on a Dual or Quad core computer (which most are any more) then proper thread tuning is very important.

You could look at OmniThread Library by Gabr, but there are a number of thread libraries in development for Delphi. You could easily implement your own parallel for using anonymous types.


Solution:10

Before you do anything, identify slow parts. Do not touch working code which performs fast enough.


Solution:11

  1. Create unit tests
  2. Verify tests all pass
  3. Profile your application
  4. Refactor looking for bottlenecks and memory
  5. Repeat from Step 2 (comparing to previous pass)


Solution:12

Make intelligent use of SetLength() for strings and arrays. Optimise initialisation with FillChar or ZeroMemory.

Local variables created on stack (e.g. record types) are faster than heap allocated (objects and New()) variables.

Reuse objects rather than Destroy then create. But make sure management code for this is faster than memory manager!


Solution:13

When working with a tstringlist (or similar), set "sorted := false" until needed (if at all). Seems like a no-brainer...


Solution:14

Check heavily-used loops for calculations that could be (at least partially) pre-calculated or handled with a lookup table. Trig functions are a classic for this, but it applies to many others.


Solution:15

If you have a list, use a dynamic array of anything, even a record as follows:

This needs no classes, no freeing and access to it is very fast. Even if it needs to grow you can do this - see below. Only use TList or TStringList if you need lots of size changing flexibility.

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;  


Solution:16

Separating the program logic from user interface, refactoring, then optimizing the most-used, most resource-intensive elements independently.


Solution:17

  • Turn debugging OFF

  • Turn optimizations ON

  • Remove all references to units that you don't actually use

  • Look for memory leaks


Solution:18

Use a lot of assertions to debug, then turn them off in shipping code.


Solution:19

Turn off range and overflow checking after you have tested extensively.


Solution:20

Use the full FastMM and study the documentation and source and see if you can tweak it to your specifications.


Solution:21

For an old BDE development when I first started Delphi, I was using lots of TQuery components. Someone told me to use TTable master-detail after I explained him what I was doing, and that made the program run much faster.

Calling DisableControls can omit unnecessary UI updates.


Solution:22

When identifying records, use integers if at all possible for record comparison. While a primary key of "company name" might seem logical, the time spent generating and storing a hash of this will greatly improve overall search times.


Solution:23

If you really, really, really need to be light weight then you can shed the VCL. Take a look at the KOL & MCK. Granted if you do that then you are trading features for reduced footprint.


Solution:24

You might consider using runtime packages. This could reduce your memory foot print if there are more then one program running that is written using the same packages.


Solution:25

If you use threads, set their processor affinity. If you don't use threads yet, consider using them, or look into asynchronous I/O (completion ports) if your application does lots of I/O.


Solution:26

Consider if a DBMS database is really the perfect choice. If you are only reading data and never changing it, then a flat fixed record file could work faster, especially if the path to the data can be easily mapped (ie, one index). A trivial binary search on a fixed record file is still extremely fast.


Solution:27

  • BeginUpdate ... EndUpdate
  • ShortString vs. String
  • Use arrays instead of TStrings and TList

But the sad answer is that tuning and optimization will give you maybe 10% improvement (and it's dangerous); re-design can give you 90%. Once you really understand the goal, you often can restate the problem (and therefore the solution) in much better terms.

Cheers


Solution:28

Examine all loops, and look for ways to short circuit. If your looking for something specific and find it in a loop, then use the BREAK command to immediately bail...no sense looping thru the rest. If you know that you don't have a match, then use a CONTINUE as quickly as possible.


Solution:29

Take advantage of some of the FastCode project code. Parts of it were incorporated into VCL/RTL proper (like FastMM was), but there is more out there you can use!

Note, they have a new site they are moving too, but it seems to be a bit inactive.


Solution:30

Consider hardware issues. If you really need performance then consider the type of hard drive(s) your program and your databases are running on. There are a lot of variables especially if you are running a database. RAID is not always the best answer either.


Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Previous
Next Post »