0

So I’m trying to have a strobe like effect on a game I’m building and the way I currently have it it’s destroying my frame rate because the sleep function is also applying to the draw function. Can someone explain why this happens? And the logic that I’m failing to understand. Why can’t I just have the return happen every .5 seconds without it affecting the .1 sleep I have in my hue function?

Here’s a crude demonstration of what the code kind of does.

from random import randint
import time
def rand_intr():
    r = randint(1,256)
    time.sleep(.5)
    return r

def rand_intg():
    g = randint(1,256)
    time.sleep(.5)
    return g

def rand_intb():
    b = randint(1,256)
    time.sleep(.5)
    return b

def hue():
    r = rand_intr()
    g = rand_intg()
    b = rand_intb()
    print(r, g, b)
    print('test')
    time.sleep(.01)

while True:
    hue()
  • @lightalchemist alright awesome! But can you explain why the sleep in the first function affects the timing of hue()? – Benji Ruiztagle Oct 22 '18 at 01:46
  • 1
    While `time.sleep()` is executing, your program is *not doing anything else but sleeping*. All three of those function calls have to be entered and finished, taking half a second each, before `hue()` finally gets to its own `sleep()`. – jasonharper Oct 22 '18 at 02:01
  • @jasonharper so how do I go about having the three random integers generate every half a second while having the hue call every 60 seconds – Benji Ruiztagle Oct 22 '18 at 02:03

1 Answers1

0

The sleep function blocks the main thread. This means rand_intg does not run until rand_intr "wakes up" from its sleep. Similarly, rand_intb has to wait for rand_intg, and hue has to wait for all the previous 3 functions. This means the total time hue has to wait before it can do any work is at least the amount of time needed to complete rand_intr, rand_intg, and rand_intb.

We can understand what is happening if we modify your example slightly and look at the output.

from random import randint
import time

def log_entry_exit(f):
    def wrapped():
        print("Entered {}".format(f.__name__))
        result = f()
        print("Leaving {}".format(f.__name__))
        return result
    return wrapped

@log_entry_exit
def rand_intr():
    r = randint(1,256)
    time.sleep(.5)
    return r

@log_entry_exit
def rand_intg():
    g = randint(1,256)
    time.sleep(.5)
    return g

@log_entry_exit
def rand_intb():
    b = randint(1,256)
    time.sleep(.5)
    return b

def hue():
    r = rand_intr()
    g = rand_intg()
    b = rand_intb()
    print(r, g, b)
    print('test')
    time.sleep(.01)

while True:
    hue()

Here I just modified your functions to print a message when we enter and exit each function.

The output is

Entered rand_intr
Leaving rand_intr
Entered rand_intg
Leaving rand_intg
Entered rand_intb
Leaving rand_intb
172 206 115
test
Entered rand_intr
Leaving rand_intr
Entered rand_intg
Leaving rand_intg
Entered rand_intb
Leaving rand_intb
240 33 135
test
...

Here, the effect of each sleep on hue can be seen clearly. You don't get to print the rgb values or "test" until the previous functions have completed.

What you can do is to call your hue function periodically using a timer callback, and then modify the rgb values according to some pattern. See this stackoverflow question on executing periodic actions for an example on how to periodically execute a function using a basic time-based mechanism.

Edit

Based on your comment to @jasonharper

If you call hue every 60 seconds, it does not make sense if your calls to the functions that generate the random rgb values occur at a faster rate because any changes in the intervening time will not be seen in hue.

What you can do is call hue every 60 seconds, then generate your rgb values to have whatever pattern in there.

Modifying the answer by @kev in the post I linked to above,

import time, threading
def update():
    # Do whatever you want here. 
    # This function will be called again in 60 seconds.
    # ...

    hue()

    # Whatever other things you want to do
    # ...

    threading.Timer(60.0, update).start()

def hue():
    r = rand_intr()
    g = rand_intg()
    b = rand_intb()
    print(r, g, b)
    # Don't call sleep.

if __name__ == "__main__":
    update()

Now you should only call update once, possibly in some startup part of your code and remove all the calls to sleep in your functions.

lightalchemist
  • 10,031
  • 4
  • 47
  • 55