Search code examples
pythontimerframe-rate

Limiting Fps in python


i want my program to do a task every x frames. However it does not seem to work, due to the fact that the timer in python seems to be inaccurate. How do i get this piece of code to obey my set framerate?

import time
fps = 5
skipticks = 1/(fps*1.0)
i= 0
nextsnap=time.clock()
print skipticks, fps
while (True):
    tim= time.clock()
    i=i+1
    # this prints the fps
    #'print 'Fps at start',i, 1/(time.time()-tim)
    # this is the sleep that limits the fps
    nextsnap+=skipticks
    sleeptime = nextsnap-time.clock()
    if (sleeptime>0):
        time.sleep (sleeptime)
    else:
        print 'took too long'
    print 'Fps at end:#', i, 1/(time.clock()-tim)

this produces on my computer:

 Fps at end:# 45 4.36627853079
Fps at end:# 46 6.44119324776
Fps at end:# 47 4.53966049676
Fps at end:# 48 4.66471670624
Fps at end:# 49 7.18312473536
Fps at end:# 50 4.34786490268
Fps at end:# 51 6.5263951487
Fps at end:# 52 4.71715853908
Fps at end:# 53 4.59636712435
Fps at end:# 54 6.87201830723
Fps at end:# 55 4.31062740848

Why are there frames that are rendered too fast? And why is the fps count inaccurate?


Solution

  • If it's about mesuring the accuracy you can have with time.clock() and time.sleep(), use something as simple as possible like:

    import time
    
    fps = 5
    time_delta = 1./fps
    
    while True:
        t0 = time.clock()
        time.sleep(time_delta)
        t1 = time.clock()
        print 1. / (t1 - t0)
    

    What is your OS and what is the result of this simple mesure ?

    If it's about cleaning your code, I would separate more clearly the FPS evaluation, the processing and the sleep call. Here is an example (the loop #0 frequency displayed should be ignored).

    import time
    import random
    from itertools import count
    
    fps = 5
    loop_delta = 1./fps
    
    current_time = target_time = time.clock()
    for i in count():
        #### loop frequency evaluation
        previous_time, current_time = current_time, time.clock()
        time_delta = current_time - previous_time
        print 'loop #%d frequency: %s' % (i, 1. / time_delta)
    
        #### processing
        # processing example that sleeps a random time between 0 and loop_delta/2.
        time.sleep(random.uniform(0, loop_delta / 2.))
    
        #### sleep management
        target_time += loop_delta
        sleep_time = target_time - time.clock()
        if sleep_time > 0:
            time.sleep(sleep_time)
        else:
            print 'took too long'
    

    Also, you probably want time.time() rather than time.clock(). See time.clock() vs. time.time() - accuracy answer.