Iker Hua Iker Hua - 28 days ago 10
Python Question

python 3 time.sleep() slows down or speeds up by other programs

Hi I have a question regarding to the

time.sleep()
function in python 3. What I am trying to do is looping a list of value periodically with the rate of 0.001 second/ point. It works fine with 0.01 or higher rate. But at 0.001 or smaller, the rate is heavily affected by opening or turning off other programs.
For example, I have a list of 100 points and run with 0.001 second per point. Then it would take approximately 100*0.001 = 0.1 second to finish it. However, when I run the code, it takes way longer about 1 second to finish. Then I turn on Google Chrome and open stack overflow or quora websites, then it runs at the right speed about 0.11 second.
I am wondering if there is any solution to fix this issue or an alternative of
time.sleep()
that won't be affected by the other programs. Here is my code for testing
time.sleep()
.

import time
from timeit import default_timer as timer
import threading

my_points = [1,2,3,4,5,6,7,8,9,10,
11,12,13,14,15,16,17,18,19,20,
21,22,23,24,25,26,27,28,29,30,
31,32,33,34,35,36,37,38,39,40,
41,42,43,44,45,46,47,48,49,50,
51,52,53,54,55,56,57,58,59,60,
61,62,63,64,65,66,67,68,69,70,
71,72,73,74,75,76,77,78,79,80,
81,82,83,84,85,86,87,88,89,90,
91,92,93,94,95,96,97,98,99,100,]

def execute():
while True:
start = timer()
for i in my_points:
print (i, flush = True)
time.sleep(0.001) #Problem is here

end = timer()
print ("Total time run per cycle: ", end - start)
time.sleep(2) #To read the time

execute()

Answer

The manual entry for time.sleep

time.sleep(secs)

Suspend execution of the calling thread for the given number of seconds. The argument may be a floating point number to indicate a more precise sleep time. The actual suspension time may be less than that requested because any caught signal will terminate the sleep() following execution of that signal’s catching routine. Also, the suspension time may be longer than requested by an arbitrary amount because of the scheduling of other activity in the system.

Changed in version 3.5: The function now sleeps at least secs even if the sleep is interrupted by a signal, except if the signal handler raises an exception (see PEP 475 for the rationale).

makes it pretty clear that the actual sleep time will only approximate the requested time. I have separately read that the resolution on Windows is 1/60 s, though I don't know if that is still true.

You can do much better using the tkinter root.after function. When I run the following in IDLE

import tkinter as tk
from time import perf_counter as timer

root = tk.Tk()
n = 1000
def tick():
    global n
    if n:
        #print(n)
        root.after(1, tick)
        n -= 1
    else:
        print(timer() - start)
        root.quit()

root.after(1, tick)
start = timer()
root.mainloop()

the output is repeatably just under 1.05 seconds, very close to the target 1.00. If I uncomment the tick print statement, the time is 4.2 seconds. In IDLE, the print goes through a socket to a separate process, which is a bit slow. Running in Windows Command Prompt, the 1000 print time is 1.3 seconds. I expect that this is about what you would get outputting to a serial post as long as the recipient can keep up with the flow.

EDIT One could do something similar with the relatively new asyncio module, and with a bit more effort, even use the newer async for syntax. But I do not have the needed knowledge memorized.