Many uses Delay(1) to avoid hugging the cpu!
This is very nice and ok with most utility programs!
But how about more heavy programs, or even various games.
Or games in windowed mode!
Using Delay(1) would cause a delay of 1 (if you lucky) to 20+ microseconds.
Using no delay at all would hog the cpu, and trying to start another program
or doing anything at all would be extreemly sluggish.
So how do you get a very fast looping program that doesn't,
cause the entire multitasking of windows to choke?
The answer is (on Windows at least) to use Delay(0)
Which Delay() actualy uses the windows API Sleep() function.
The Win API documentation states:
So if you use Delay(0) instead of the more common Delay(1)A value of zero causes the thread to relinquish the remainder of its time slice to any other thread of equal priority that is ready to run.
If there are no other threads of equal priority ready to run, the function returns immediately, and the thread continues execution.
to avoid eating up CPU,
you will notice cpu usage go from ~1% cpu load to whatever
the idle cpu of the system is.
In other words. if you have 95% free cpu and you start the program
and it uses Delay(0) instead of 1. it will use 95% cpu.
The advantage should be obvious.
A. Windows itself (which should have one of the highest priorities) will not become sluggish!
B. Starting of quitting programs may be a bit slower, but not annoying!
C. You avoid hogging the cpu, yet able to use a optimal loop!
D. Changing the program priority will actually be even more usefull than before!
Below is the source for a test program of mine.
Run it and note down the number displayed when the test is done!
Change the Delay(0) on line 56 to a Delay(1)
and watch the programs performance drop!
(Warning! You could try commenting out the Delay(0) but be aware
your system will be sluggish as hell for 60 seconds).
With the delay set at Delay(0) my system (Athlon 1.85Ghz)
shows a rating of: 1817
This test program simply meassures the number of loops that occur
over the time of 60 seconds.
But calculates the result from the microseconds for a more accurate and sensible result.
My rating above of 1817 means that 1817 loops occured on average each 1 microsecond.
That means 1817000 loops per second, and 109020000 loops during 60 seconds.
So remember, 1817 in this case is how many loops in one microsecond.
If you change the delay to 1 you won't even get 1 loop,
more likely to get 0.1 or less, as a Delay(1) can give a delay of 1ms to 20+ ms depending on your system.
Delay(0) does not delay at all, it simply enforces a task switch.
(or in other words "multitasking")
The higher the rating the faster your system is able to multitask,
so this is your chance to brag. (we all love benchmark programs right? hehe)
But seriously, this example (yet usefull) program shows how to use Delay(0)
so you can get maximum loopability/response in your program,
while avoding hogging the system.
Essentially what happens is that with Delay(0) on Windows
is that your program will use whatever cpu the "system" gives it,
versus no delay where it would even steal from Windows itself.
Obviously as you start throwing more program code into the loop
and other stuff and procedures, the number of loops will be less,
yet way more loops/response than if you had used a delay of 1ms.
Have fun with the code peeps! It's freeware, no commercial use permitted,
however feel free to borrow the code and use it in your own programs.
I've begun using a Delay(1) on all non-critical programs I make.
(simple tools, or programs that usually wait purely for user input)
and Delay(0) on programs that are autonomous, or in other words
do things on their own. like showing graphics on the screen etc.
Imagine this:
Using Delay(0) on a system similar to mine you are able to do over 1800 loops per microsecond.
That is over 1.8 million loops per second. (multitasking loops)
That means, while the graphics update say, 85 times per second. (85Hz)
the game itself would be able to do over a million calculations per second,
without making the system sluggish.
If you were to use no loop, you would be able to do way more loops.
But the system would be sluggish or non-responsive.
And if you were to use a delay of 1 ms then you could end up with as much as 20+ ms delay.
and 1000ms (1 sec) divided by 85 (Hz) is 11,764 ms (per Hz).
Meaning, there is no way you could have 85 loops/updates per sec to match the refresh rate of a system (or the graphics).
At 85Hz you actually need 85000 "loops" to sync the game data with the refresh rate.
However if you use Delay(0) you are able to do over a million updates per second.
I have no idea if Delay(0) behave the same on Linux and Mac and Amiga, but hopefully they. (if anyone know, or Fred you have the time) it would be nice if someone mentioned that here!
Here's the code, have fun!
Code: Select all
; (c) Roger Hågensen, EmSai 2005
title$="Multitask Loop v0.1"
text$="This test will take about 60 seconds."+#CRLF$+#CRLF$+"To ensure an accurate test, please do not use the computer during the test!"+#CRLF$+#CRLF$
Enumeration
#Window
EndEnumeration
Enumeration
#Gadget_Info
#Gadget_Start
#Gadget_Abort
EndEnumeration
If OpenWindow(#Window,0,0,200,185,title$,#PB_Window_SystemMenu|#PB_Window_TitleBar|#PB_Window_ScreenCentered)
EditorGadget(#Gadget_Info,10,10,180,130,#PB_String_ReadOnly|#PB_String_BorderLess|#ESB_DISABLE_LEFT|#ESB_DISABLE_RIGHT)
ButtonGadget(#Gadget_Start,15,140,70,35,"S T A R T")
ButtonGadget(#Gadget_Abort,115,140,70,35,"A B O R T")
DisableGadget(#Gadget_Start,0)
DisableGadget(#Gadget_Abort,1)
Else
MessageRequester(title$,"Unable to open window!")
End
EndIf
Repeat
Event=WindowEvent()
If Event=#PB_Event_Gadget
gadget=EventGadget()
If gadget=#Gadget_Start
DisableGadget(#Gadget_Start,1)
DisableGadget(#Gadget_Abort,0)
SetGadgetText(#Gadget_Info,text$+"Starting...")
While WindowEvent()
Wend
gadget=0
loopcount=0
Delay(1000)
SetGadgetText(#Gadget_Info,text$+"Please wait...")
Delay(1000)
Started=ElapsedMilliseconds()
StartTime=Started
Repeat
Event=WindowEvent()
If Event=#PB_Event_Gadget
gadget=EventGadget()
EndIf
; do some test code here
; end test code
Delay(0) ;no delay, just tell the system to go to next task in cpu queue!
CurrentTime=ElapsedMilliseconds()
ElapsedTime=CurrentTime-StartTime
loopcount+1
ended=ElapsedMilliseconds()-Started
Until gadget=#Gadget_Abort Or ended>59999
Event=0
If gadget=#Gadget_Abort
SetGadgetText(#Gadget_Info,text$)
Else
SetGadgetText(#Gadget_Info,text$+"Rating: "+StrF(loopcount/ended,3)+" (loops/ms)")
EndIf
DisableGadget(#Gadget_Start,0)
DisableGadget(#Gadget_Abort,1)
EndIf
EndIf
Delay(1)
Until Event=#PB_Event_CloseWindow
While WindowEvent()
Wend
CloseWindow(#Window)
End