Reputation: 421
I came across an interesting issue when discussing timing precision on the psychopy forum (psychopy is a psychology software written in python). Here's the problem:
timer=core.Clock()#instantiate a clock
stimulus.draw()#draw stimulus
win.flip()#flip the monitor to make stimulus appear
Routine = True
While Routine:
key_press = event.getKeys(keyList=["f", "j"])#check keyboard's buffer
if len(key_press) > 0:#keypress detected!
RT = timer.getTime()#record response time
Routine = False
I've been told that calling getTime() within a while loop can be dangerous : "A very tight loop hogs all the CPU time to itself, choking other processes, which might just eventually break in and seize control for quite a while to get through a backlog, completely mucking up your timing. On each iteration, call something like time.sleep(0.001) to yield time to other processes." I don't see why it would be. Can somebody shed light on this programming issue?
Upvotes: 1
Views: 929
Reputation: 2359
I'll have a go at answering, based off the discussion found at How would I stop a while loop after n amount of time?, and specifically Anthony's comment: https://stackoverflow.com/a/44723559/8763097
while True:
loops tend to hog the CPU processes in what, I think, is termed: Busy Waiting
Busy-waiting, busy-looping or spinning is a technique in which a process repeatedly checks to see if a condition is true, such as whether keyboard input or a lock is available.
Busy-waiting itself can be made much less wasteful by using a delay function (e.g., sleep()) found in most operating systems. This puts a thread to sleep for a specified time, during which the thread will waste no CPU time. If the loop is checking something simple then it will spend most of its time asleep and will waste very little CPU time.
So your while loop is spending a lot of time checking the if statement value of len(key_press)
over and over and over. Adding a sleep()
routine will allow the While loop to pause, whereby other processes can take place.
This may be why you report inconsistencies in your time function - the function .core.getTime() is not a core python function. It's part of the core of your psychopy package, and it doesn't look like a process clock...it looks like a basic clock timer. As such, the timer may be influenced by the While loop's CPU hogging. Without knowing any more about your package's clock handling, however, this is simply a guess.
Perhaps to avoid this problem, consider using time.perf_counter()
with a sleep function as this will include any sleep()
time within the count.
EDIT 1: Perhaps one solution is to work with the MS VC++ Runtime library, which is couched within Python's core.
import msvcrt
import time
print("GO")
start = time.perf_counter()
while True:
if msvcrt.kbhit():
end = time.perf_counter()
print(end-start)
break
The library should be able to handle the command to wait for a keyboard press before moving to the next step in the loop. Does it solve the problem? Not quite. Can the problem really be solved? I'm not sure...
Upvotes: 1