Python loop delay without time.sleep() - python

In an MMO game client, I need to create a loop that will loop 30 times in 30 seconds (1 time every second).
To my greatest disappointment, I discovered that I can not use time.sleep() inside the loop because that causes the game to freeze during the loop.
The loop itself is pretty simple and the only difficulty is how to delay it.
limit = 31
while limit > 0 :
print "%s seconds remaining" % (limit)
limit = limit -1
The python libs exist in the client as .pyc files in a separate folder and I'm hoping that I can avoid messing with them.
Do you think that there is any way to accomplish this delay or is it a dead end?

Your game has a main loop. (Yes, it does.)
Each time through the loop when you go to check state, move the players, redraw the screen, etc., you check the time left on your timer. If at least 1 second has elapsed, you print out your "seconds remaining" quip. If At least 30 seconds has elapsed, you trigger whatever your action is.

You can't do it without blocking or threading unless you are willing to lose precision...
I'd suggest sometime like this, but threading is the correct way to do this...
import time
counter = 31
start = time.time()
while True:
### Do other stuff, it won't be blocked
time.sleep(0.1)
print "looping..."
### When 1 sec or more has elapsed...
if time.time() - start > 1:
start = time.time()
counter = counter - 1
### This will be updated once per second
print "%s seconds remaining" % counter
### Countdown finished, ending loop
if counter <= 0:
break
or even...
import time
max = 31
start = time.time()
while True:
### Do other stuff, it won't be blocked
time.sleep(0.1)
print "looping..."
### This will be updated every loop
remaining = max + start - time.time()
print "%s seconds remaining" % int(remaining)
### Countdown finished, ending loop
if remaining <= 0:
break

Related

Iterating through next after a certain amount of time

Let's say that I have the following code:
possibilities = range(20)
input_name = 4
for i in possibilities:
exec("import Function_" + str(i))
exec("Function_" + str(i) + ".solveproblem(" + str(input_name) + ")")
Since the second exec function, e.g. Function_3.solveproblem(4), can take infinity amount of time, I would just like to try (the function also can have some error) at most for 1,000 seconds and if the time exceeds, then I would like to stop that execution and go through the next function from another python file.
Any idea?
You could try a timer with time
base = time.time() # Get time before start
for each in possibilities:
''do your stuff''
if time.time()-base>100:
break # Time limit
Or if it is impossible to slide it in, consider starting another thread
def timer:
base = time.time() # Get time before start
while True:
if time.time()-base==100:
thread.interrupt_main()
break # Time limit
thread = threading.Thread(target=timer)
thread.start()
'''
now do the rest
'''
How to exit the entire application from a Python thread?

Python - Accurate time.sleep

I am working on a project which accurate timer is really crucial. I am working on python and am using timer.sleep() function.
I noticed that timer.sleep() function will add additional delay because of the scheduling problem (refer to timer.sleep docs). Due to that issue, the longer my program runs, the more inaccurate the timer is.
Is there any more accurate timer/ticker to sleep the program or solution for this problem?
Any help would be appreciated. Cheers.
I had a solution similar to above, but it became processor heavy very quickly. Here is a processor-heavy idea and a workaround.
def processor_heavy_sleep(ms): # fine for ms, starts to work the computer hard in second range.
start = time.clock()
end = start + ms /1000.
while time.clock() < end:
continue
return start, time.clock()
def efficient_sleep(secs, expected_inaccuracy=0.5): # for longer times
start = time.clock()
end = secs + start
time.sleep(secs - expected_inaccuracy)
while time.clock() < end:
continue
return start, time.clock()
output of efficient_sleep(5, 0.5) 3 times was:
(3.1999303695151594e-07, 5.0000003199930365)
(5.00005983869791, 10.00005983869791)
(10.000092477987678, 15.000092477987678)
This is on windows. I'm running it for 100 loops right now. Here are the results.
(485.003749358414, 490.003749358414)
(490.0037919174879, 495.0037922374809)
(495.00382903668014, 500.00382903668014)
The sleeps remain accurate, but the calls are always delayed a little. If you need a scheduler that accurately calls every xxx secs to the millisecond, that would be a different thing.
the longer my program runs, the more inaccurate the timer is.
So, for example by expecting 0.5s delay, it will be time.sleep(0.5 - (start-end)). But still didn't solve the issue
You seem to be complaining about two effects, 1) the fact that timer.sleep() may take longer than you expect, and 2) the inherent creep in using a series of timer.sleep() calls.
You can't do anything about the first, short of switching to a real-time OS. The underlying OS calls are defined to sleep for at least as long as requested. They only guarantee that you won't wake early; they make no guarantee that you won't wake up late.
As for the second, you ought to figure your sleep time according to an unchanging epoch, not from your wake-up time. For example:
import time
import random
target = time.time()
def myticker():
# Sleep for 0.5s between tasks, with no creep
target += 0.5
now = time.time()
if target > now:
time.sleep(target - now)
def main():
previous = time.time()
for _ in range(100):
now = time.time()
print(now - previous)
previous = now
# simulate some work
time.sleep(random.random() / 10) # Always < tick frequency
# time.sleep(random.random()) # Not always < tick frequency
myticker()
if __name__ == "__main__":
main()
Working on Linux with zero knowledge of Windows, I may be being naive here but is there some reason that writing your own sleep function, won't work for you?
Something like:
import time
def sleep_time():
start_time = time.time()
while (time.time() - start_time) < 0.0001:
continue
end_time = time.time() + 60 # run for a minute
cnt = 0
while time.time() < end_time:
cnt += 1
print('sleeping',cnt)
sleep_time()
print('Awake')
print("Slept ",cnt," Times")

Make a timer using sleep in python. How to account for computation time?

I'm trying to make a simple timer which prints the time remaining every second.
for k in range(100):
print(100-k)
t.sleep(1)
#output
#100
#99
#98
#...
#1
However, this will take slightly longer than 100 seconds, because there will be a delay added when print() is used. For long periods, this is slightly noticeable. Is there a way to account for this, and accurately display the time every second? I know I could just sleep(100), but this wouldn't let the time left be printed.
import time
start_time=time.time()
for k in range(25):
print(25-k)
time.sleep(1)
print("it took "+str(float(time.time()-start_time)*1000)+" Milliseconds")
the output with print is: it took 26412.75382041931 Milliseconds
the output without print : it took 25053.035020828247 Milliseconds
it should have been just 25000 milliseconds but it is not
printing will take time, even reading the code takes time
point is don't expect accurate timing with time.sleep() !!!
You can use time.time() to measure elapsed time.
import time
start_time = time.time()
for k in range(100):
# k seconds SHOULD be elapsed at this point
print(100 - k)
slept_time = time.time() - start_time
time.sleep(1 + k-slept_time)
Using time.sleep will never give you the accurate time for your timer, since the time it takes is the one second sleep time + printing time, you can use threading.Timer to get more accurate results. https://repl.it/Hwkt :
import threading, time
start_time=time.time()
def count_loop(counter):
if counter <= 0:
print("it took "+str(float(time.time()-start_time)*1000)+" Milliseconds")
return
threading.Timer(1.0, count_loop, args=[counter-1]).start()
print(counter)
count_loop(100)
This is still not accurate, but with only very minimum offset, only 45 ms. However, when using time.sleep from legendisback's example, there is apparently 81 ms delay. https://repl.it/HwlK

What is the best/most efficient way to output value every x seconds during a loop

I have always been curious about this as the simple way is definitely not efficient. How would you efficiently go about outputting a value every x seconds?
Here is an example of what I mean:
import time
num = 50000000
startTime = time.time()
j=0
for i in range(num):
j = (((j+10)**0.5)**2)**0.5
print time.time() - startTime
#output time: 24 seconds
startTime = time.time()
newTime = time.time()
j=0
for i in range(num):
j = (((j+10)**0.5)**2)**0.5
if time.time() - newTime > 0.5:
newTime = time.time()
print i
print time.time() - startTime
#output time: 32 seconds
A whole 1/3rd faster when not outputting the progress every half a second.
I know this is because it requires an extra calculation every loop, but the same applies with other similar checks you may want to do - how would you go about implementing something like this without seriously affecting the execution time?
Well, you know that you're doing many iterations per second, so you really don't need to make the time.time() call on every iteration. You can use a modulo operator to only actually check if you need to output something every N iterations of the loop.
startTime = time.time()
newTime = time.time()
j=0
for i in range(num):
j = (((j+10)**0.5)**2)**0.5
if i % 50 == 0: # Only check every 50th iteration
if time.time() - newTime > 0.5:
newTime = time.time()
print i, newTime
print time.time() - startTime
# 45 seconds (the original version took 42 on my system)
Checking only every 50 iterations reduces my run time from 56 seconds to 43 (the original took with no printing 42, and Tom Page's solution took 50 seconds), and the iterations complete quickly enough that its still outputting exactly every 0.5 seconds according to time.time():
0 1409083225.39
605000 1409083225.89
1201450 1409083226.39
1821150 1409083226.89
2439250 1409083227.39
3054400 1409083227.89
3644100 1409083228.39
4254350 1409083228.89
4831600 1409083229.39
5433450 1409083229.89
6034850 1409083230.39
6644400 1409083230.89
7252650 1409083231.39
7840100 1409083231.89
8438300 1409083232.39
9061200 1409083232.89
9667350 1409083233.39
...
You might save a few clock cycles by keeping track of the next time that a print is due
nexttime = time.time() + 0.5
And then your condition will be a simple comparison
If time.time() >= nexttime
As opposed to a subtraction followed by a comparison
If time.time() - newTime > 0.5
You'll only have to do an addition after each message as opposed to doing a subtraction after each itteration
I tried it with a sideband thread doing the printing. It added 5 seconds to exec time on python 2.x but virtually not extra time on python 3.x. Python 2.x threads have a lot of overhead. Here's my example with timing included as comments:
import time
import threading
def showit(event):
global i # could pass in a mutable object instead
while not event.is_set():
event.wait(.5)
print 'value is', i
num = 50000000
startTime = time.time()
j=0
for i in range(num):
j = (((j+10)**0.5)**2)**0.5
print time.time() - startTime
#output time: 23 seconds
event = threading.Event()
showit_thread = threading.Thread(target=showit, args=(event,))
showit_thread.start()
startTime = time.time()
j=0
for i in range(num):
j = (((j+10)**0.5)**2)**0.5
event.set()
time.sleep(.1)
print time.time() - startTime
#output time: 28 seconds
If you want to wait a specified period of time before doing something, just use the time.sleep() method.
for i in range(100):
print(i)
time.sleep(0.5)
This will wait half a second before printing the next value of i.
If you don't care about Windows, signal.setitimer will be simpler than using a background thread, and on many *nix platforms a whole lot more efficient.
Here's an example:
import signal
import time
num = 50000000
startTime = time.time()
def ontimer(sig, frame):
global i
print(i)
signal.signal(signal.SIGVTALRM, ontimer)
signal.setitimer(signal.ITIMER_VIRTUAL, 0.5, 0.5)
j=0
for i in range(num):
j = (((j+10)**0.5)**2)**0.5
signal.setitimer(signal.ITIMER_VIRTUAL, 0)
print(time.time() - startTime)
This is about as close to free as you're going to get performance-wise.
In some use cases, a virtual timer isn't sufficiently accurate, so you need to change that to ITIMER_REAL and change the signal to SIGALRM. That's a little more expensive, but still pretty cheap, and still dead simple.
On some (older) *nix platforms, alarm may be more efficient than setitmer, but unfortunately alarm only takes integral seconds, so you can't use it to fire twice/second.
Timings from my MacBook Pro:
no output: 15.02s
SIGVTALRM: 15.03s
SIGALRM: 15.44s
thread: 19.9s
checking time.time(): 22.3s
(I didn't test with either dano's optimization or Tom Page's; obviously those will reduce the 22.3, but they're not going to get it down to 15.44…)
Part of the problem here is that you're using time.time.
On my MacBook Pro, time.time takes more than 1/3rd as long as all of the work you're doing:
In [2]: %timeit time.time()
10000000 loops, best of 3: 105 ns per loop
In [3]: %timeit (((j+10)**0.5)**2)**0.5
1000000 loops, best of 3: 268 ns per loop
And that 105ns is fast for time—e.g., an older Windows box with no better hardware timer than ACPI can take 100x longer.
On top of that, time.time is not guaranteed to have enough precision to do what you want anyway:
Note that even though the time is always returned as a floating point number, not all systems provide time with a better precision than 1 second.
Even on platforms where it has better precision than 1 second, it may have a lower accuracy; e.g., it may only be updated once per scheduler tick.
And time isn't even guaranteed to be monotonic; on some platforms, if the system time changes, time may go down.
Calling it less often will solve the first problem, but not the others.
So, what can you do?
Unfortunately, there's no built-in answer, at least not with Python 2.7. The best solution is different on different platforms—probably GetTickCount64 on Windows, clock_gettime with the appropriate clock ID on most modern *nixes, gettimeofday on most other *nixes. These are relatively easy to use via ctypes if you don't want to distribute a C extension… but someone really should wrap it all up in a module and post it on PyPI, and unfortunately I couldn't find one…

Pygame simple score system

I have created a simple score system for my pygame. but it's pausing the game. I know it's because of time.sleep but I don't how to sort it out.
The score system is to +100 every 5 seconds while start is true, code:
while start == True:
time.sleep(5)
score = score + 100
Full code with indentation: http://pastebin.com/QLd3YTdJ
code at line : 156-158
Thank you
Instead of using sleep, which stalls the game until time has elapsed, you want to count up an internal timer with the number of seconds which have passed. When you hit 5 seconds, increment the score and then reset the timer.
Something like this:
scoreIncrementTimer = 0
lastFrameTicks = pygame.time.get_ticks()
while start == True:
thisFrameTicks = pygame.time.get_ticks()
ticksSinceLastFrame = thisFrameTicks - lastFrameTicks
lastFrameTicks = thisFrameTicks
scoreIncrementTimer = scoreIncrementTimer + ticksSinceLastFrame
if scoreIncrementTimer > 5000:
score = score + 100
scoreIncrementTimer = 0
This could easily be improved (what if your frame rate is so low there's more than 5 seconds between frames?) but is the general idea. This is commonly called a "delta time" game timer implementation.
If i understand you correctly you dont want the while True: score += 100 loop to block your entire program?
You should solve it by moving the score adding to a seperate function
and use the intervalfunction of APScheduler http://packages.python.org/APScheduler/intervalschedule.html
from apscheduler.scheduler import Scheduler
# Start the scheduler
sched = Scheduler()
sched.start()
# Schedule job_function to be called every 5 seconds
#sched.interval_schedule(seconds=5)
def incr_score():
score += 100
This will result in APScheduler creating a thread for you running the function every 5 seconds.
you might need to do some changes to the function to make it work but it should get you started at least :).

Categories