可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I\'m having difficulties with the python timer and would greatly appreciate some advice or help :D
I\'m not too knowledgeable of how threads work, but I just want to fire off a function every 0.5 seconds and be able to start and stop and reset the timer.
However, I keep getting RuntimeError: threads can only be started once
when I execute threading.timer.start()
twice. Is there a work around for this? I tried applying threading.timer.cancel()
before each start.
Pseudo code:
t=threading.timer(0.5,function)
while True:
t.cancel()
t.start()
回答1:
The best way is to start the timer thread once. Inside your timer thread you\'d code the following
class MyThread(Thread):
def __init__(self, event):
Thread.__init__(self)
self.stopped = event
def run(self):
while not self.stopped.wait(0.5):
print(\"my thread\")
# call a function
In the code that started the timer, you can then set
the stopped event to stop the timer.
stopFlag = Event()
thread = MyThread(stopFlag)
thread.start()
# this will stop the timer
stopFlag.set()
回答2:
Using timer threads-
from threading import Timer,Thread,Event
class perpetualTimer():
def __init__(self,t,hFunction):
self.t=t
self.hFunction = hFunction
self.thread = Timer(self.t,self.handle_function)
def handle_function(self):
self.hFunction()
self.thread = Timer(self.t,self.handle_function)
self.thread.start()
def start(self):
self.thread.start()
def cancel(self):
self.thread.cancel()
def printer():
print \'ipsem lorem\'
t = perpetualTimer(5,printer)
t.start()
this can be stopped by t.cancel()
回答3:
From Equivalent of setInterval in python:
import threading
def setInterval(interval):
def decorator(function):
def wrapper(*args, **kwargs):
stopped = threading.Event()
def loop(): # executed in another thread
while not stopped.wait(interval): # until stopped
function(*args, **kwargs)
t = threading.Thread(target=loop)
t.daemon = True # stop if the program exits
t.start()
return stopped
return wrapper
return decorator
Usage:
@setInterval(.5)
def function():
\"...\"
stop = function() # start timer, the first call is in .5 seconds
stop.set() # stop the loop
stop = function() # start new timer
# ...
stop.set()
Or here\'s the same functionality but as a standalone function instead of a decorator:
cancel_future_calls = call_repeatedly(60, print, \"Hello, World\")
# ...
cancel_future_calls()
Here\'s how to do it without using threads.
回答4:
In the interest of providing a correct answer using Timer as the OP requested, I\'ll improve upon swapnil jariwala\'s answer:
from threading import Timer
import time
class InfiniteTimer():
\"\"\"A Timer class that does not stop, unless you want it to.\"\"\"
def __init__(self, seconds, target):
self._should_continue = False
self.is_running = False
self.seconds = seconds
self.target = target
self.thread = None
def _handle_target(self):
self.is_running = True
self.target()
self.is_running = False
self._start_timer()
def _start_timer(self):
if self._should_continue: # Code could have been running when cancel was called.
self.thread = Timer(self.seconds, self._handle_target)
self.thread.start()
def start(self):
if not self._should_continue and not self.is_running:
self._should_continue = True
self._start_timer()
else:
print(\"Timer already started or running, please wait if you\'re restarting.\")
def cancel(self):
if self.thread is not None:
self._should_continue = False # Just in case thread is running and cancel fails.
self.thread.cancel()
else:
print(\"Timer never started or failed to initialize.\")
def tick():
print(\'ipsem lorem\')
# Example Usage
t = InfiniteTimer(0.5, tick)
t.start()
The import time is optional without the example usage.
回答5:
I have changed some code in swapnil-jariwala code to make a little console clock.
from threading import Timer, Thread, Event
from datetime import datetime
class perpetualTimer():
def __init__(self, t, hFunction):
self.t = t
self.hFunction = hFunction
self.thread = Timer(self.t, self.handle_function)
def handle_function(self):
self.hFunction()
self.thread = Timer(self.t, self.handle_function)
self.thread.start()
def start(self):
self.thread.start()
def cancel(self):
self.thread.cancel()
def printer():
tempo = datetime.today()
print(\"{}:{}:{}\".format(tempo.hour, tempo.minute, tempo.second))
t = perpetualTimer(1, printer)
t.start()
OUTPUT
>>> 11:39:11
11:39:12
11:39:13
11:39:14
11:39:15
11:39:16
...
Timer with a tkinter Graphic interface
This code puts the clock timer in a little window with tkinter
from threading import Timer, Thread, Event
from datetime import datetime
import tkinter as tk
app = tk.Tk()
lab = tk.Label(app, text=\"Timer will start in a sec\")
lab.pack()
class perpetualTimer():
def __init__(self, t, hFunction):
self.t = t
self.hFunction = hFunction
self.thread = Timer(self.t, self.handle_function)
def handle_function(self):
self.hFunction()
self.thread = Timer(self.t, self.handle_function)
self.thread.start()
def start(self):
self.thread.start()
def cancel(self):
self.thread.cancel()
def printer():
tempo = datetime.today()
clock = \"{}:{}:{}\".format(tempo.hour, tempo.minute, tempo.second)
try:
lab[\'text\'] = clock
except RuntimeError:
exit()
t = perpetualTimer(1, printer)
t.start()
app.mainloop()
An example of flashcards game (sort of)
from threading import Timer, Thread, Event
from datetime import datetime
class perpetualTimer():
def __init__(self, t, hFunction):
self.t = t
self.hFunction = hFunction
self.thread = Timer(self.t, self.handle_function)
def handle_function(self):
self.hFunction()
self.thread = Timer(self.t, self.handle_function)
self.thread.start()
def start(self):
self.thread.start()
def cancel(self):
self.thread.cancel()
x = datetime.today()
start = x.second
def printer():
global questions, counter, start
x = datetime.today()
tempo = x.second
if tempo - 3 > start:
show_ans()
#print(\"\\n{}:{}:{}\".format(tempo.hour, tempo.minute, tempo.second), end=\"\")
print()
print(\"-\" + questions[counter])
counter += 1
if counter == len(answers):
counter = 0
def show_ans():
global answers, c2
print(\"It is {}\".format(answers[c2]))
c2 += 1
if c2 == len(answers):
c2 = 0
questions = [\"What is the capital of Italy?\",
\"What is the capital of France?\",
\"What is the capital of England?\",
\"What is the capital of Spain?\"]
answers = \"Rome\", \"Paris\", \"London\", \"Madrid\"
counter = 0
c2 = 0
print(\"Get ready to answer\")
t = perpetualTimer(3, printer)
t.start()
output:
Get ready to answer
>>>
-What is the capital of Italy?
It is Rome
-What is the capital of France?
It is Paris
-What is the capital of England?
...
回答6:
Improving a little on Hans Then\'s answer, we can just subclass the Timer function. The following becomes our entire \"repeat timer\" code, and it can be used as a drop-in replacement for threading.Timer with all the same arguments:
from threading import Timer
class RepeatTimer(Timer):
def run(self):
while not self.finished.wait(self.interval):
self.function(*self.args, **self.kwargs)
Usage example:
def dummyfn(msg=\"foo\"):
print(msg)
timer = RepeatTimer(1, dummyfn)
timer.start()
time.sleep(5)
timer.cancel()
produces the following output:
foo
foo
foo
foo
and
timer = RepeatTimer(1, dummyfn, args=(\"bar\",))
timer.start()
time.sleep(5)
timer.cancel()
produces
bar
bar
bar
bar
回答7:
I had to do this for a project. What I ended up doing was start a separate thread for the function
t = threading.Thread(target =heartbeat, args=(worker,))
t.start()
****heartbeat is my function, worker is one of my arguments****
inside of my heartbeat function:
def heartbeat(worker):
while True:
time.sleep(5)
#all of my code
So when I start the thread the function will repeatedly wait 5 seconds, run all of my code, and do that indefinitely. If you want to kill the process just kill the thread.
回答8:
I have implemented a class that works as a timer.
I leave the link here in case anyone needs it:
https://github.com/ivanhalencp/python/tree/master/xTimer
回答9:
from threading import Timer
def TaskManager():
#do stuff
t = Timer( 1, TaskManager )
t.start()
TaskManager()
Here is small sample, it will help beter understanding how it runs.
function taskManager() at the end create delayed function call to it self.
Try to change \"dalay\" variable and you will able to see difference
from threading import Timer, _sleep
# ------------------------------------------
DATA = []
dalay = 0.25 # sec
counter = 0
allow_run = True
FIFO = True
def taskManager():
global counter, DATA, delay, allow_run
counter += 1
if len(DATA) > 0:
if FIFO:
print(\"[\"+str(counter)+\"] new data: [\"+str(DATA.pop(0))+\"]\")
else:
print(\"[\"+str(counter)+\"] new data: [\"+str(DATA.pop())+\"]\")
else:
print(\"[\"+str(counter)+\"] no data\")
if allow_run:
#delayed method/function call to it self
t = Timer( dalay, taskManager )
t.start()
else:
print(\" END task-manager: disabled\")
# ------------------------------------------
def main():
DATA.append(\"data from main(): 0\")
_sleep(2)
DATA.append(\"data from main(): 1\")
_sleep(2)
# ------------------------------------------
print(\" START task-manager:\")
taskManager()
_sleep(2)
DATA.append(\"first data\")
_sleep(2)
DATA.append(\"second data\")
print(\" START main():\")
main()
print(\" END main():\")
_sleep(2)
DATA.append(\"last data\")
allow_run = False