Article ID: | qGEN006 |
Date Revised: | November 14, 1998 |
Keywords: | DoEvents, OOP, FastDoEvents |
Question: After adding a DoEvents command in my loop the performance has degraded. How can I speed it back up?
Answer: Calling DoEvents is just plain slow.
lnStart = seconds()
for i = 1 to 100
DoEvents
endfor
? "Time to execute 100 DoEvents:", seconds() - lnStart
On a P166 running Win95 the above code takes an average of 26 seconds to execute, so each call to DoEvents takes a whopping 0.26 seconds!
There isn't too big a need to execute a DoEvents for every iteration of a tight loop, once every 100 or 1000 iterations is typically fast enough. A second counter can be used to control a conditional call to DoEvents(). Wrapping all of this into an object is trivial:
define class DoEventsControl as Line
mnIterationCount = 0
mnIterationLimit = 1000
procedure Init( pnIterationLimit )
if ( pcount() = 1 )
this.mnIterationLimit = m.pnIterationLimit
endif
endproc
procedure Execute( plForced )
with this
.mnIterationCount = ( .mnIterationCount + 1 ) % .mnIterationLimit
if ( .mnIterationCount = 0 ) or m.plForced
DoEvents
endif
endwith
endproc
enddefine
So the above loop can be rewritten as:
lnStart = seconds()
oDoEvents = createobject( "DoEventsControl" )
for i = 1 to 10000
oDoEvents.Execute()
endfor
oDoEvents.Release()
? "Time to execute 10,000 calls", seconds() - lnStart
The above code which only makes 10 DoEvents calls executes in 2.9 seconds which means the oDoEvents only adds 0.3 seconds for 10,000 iterations.
Update 14-Nov-98
Recently while working on an application I noticed an oddity in the speed of DoEvents under VFP6. While reporting the problem one of the Microsoft engineers noticed that DoEvents runs orders of magnitude faster if the mouse was moving. So that revelation spawned this alternative to DoEvents:
* FastDoEvents.prg 30-Sep-98
* 07-Nov-98 added keyboard for when mouse is out of VFP
* this workaround speeds up a DoEvent call
local lnRow, lnCol, lcWindow
lcWindow = wontop()
lnRow = mrow( lcWindow )
lnCol = mcol( lcWindow )
if ( lnRow > 0 ) and ( lnCol > 0 )
* mouse still within VFP window, so it's ok to mouse
mouse at mrow(), mcol() window (lcWindow)
else
keyboard " "
=inkey()
endif
DoEvents
FastDoEvents() executes on the order of 0.6 milliseconds per call making it 433 times faster!
The keyboard addition came after a thread of discussion with George Tasker over on the UniversalThread. The DoEventsControl class above can be modified to take further advantage of the workaround:
procedure Execute( plForced )
with this
.mnIterationCount = ( .mnIterationCount + 1 ) % .mnIterationLimit
if ( .mnIterationCount = 0 ) or m.plForced
FastDoEvents()
endif
endwith
endproc