Équivalent de setInterval en python
j'ai récemment posté une question sur la façon de reporter l'exécution d'une fonction en Python (sorte d'équivalent à Javascript setTimeout
) et il s'avère être une tâche simple en utilisant threading.Timer
(bien, simple aussi longtemps que la fonction ne partage pas d'état avec un autre code, mais qui créerait des problèmes dans n'importe quel environnement piloté par un événement).
maintenant j'essaie de faire mieux et d'imiter setInterval
. Pour ceux qui ne connaissent pas avec Javascript setInterval
permet de répéter un appel à une fonction toutes les x secondes, sans bloquer l'exécution du code. J'ai créé cet exemple décorateur:
import time, threading
def setInterval(interval, times = -1):
# This will be the actual decorator,
# with fixed interval and times parameter
def outer_wrap(function):
# This will be the function to be
# called
def wrap(*args, **kwargs):
# This is another function to be executed
# in a different thread to simulate setInterval
def inner_wrap():
i = 0
while i != times:
time.sleep(interval)
function(*args, **kwargs)
i += 1
threading.Timer(0, inner_wrap).start()
return wrap
return outer_wrap
à utiliser comme suit
@setInterval(1, 3)
def foo(a):
print(a)
foo('bar')
# Will print 'bar' 3 times with 1 second delays
et il me semble qu'il fonctionne bien. Mon problème est que
- il semble trop compliqué, et j'ai peur d'avoir loupé une plus simple/mieux mécanisme de
- le le décorateur peut être appelé sans le deuxième paramètre, dans ce cas il ne s'arrêtera jamais. Quand je dis foreover, je veux dire forever - même appeler
sys.exit()
à partir du fil principal ne l'arrêtera pas, ni ne frapperaCtrl+c
. La seule façon de l'arrêter est de tuer python processus à partir de l'extérieur. Je voudrais pouvoir envoyer un signal depuis le thread principal qui arrêterait le callback. Mais je suis un débutant avec des fils-Comment puis-je communiquer entre eux?
MODIFIER Au cas où quelqu'un merveilles, c'est la version finale du décorateur, grâce à l'aide de jd
import threading
def setInterval(interval, times = -1):
# This will be the actual decorator,
# with fixed interval and times parameter
def outer_wrap(function):
# This will be the function to be
# called
def wrap(*args, **kwargs):
stop = threading.Event()
# This is another function to be executed
# in a different thread to simulate setInterval
def inner_wrap():
i = 0
while i != times and not stop.isSet():
stop.wait(interval)
function(*args, **kwargs)
i += 1
t = threading.Timer(0, inner_wrap)
t.daemon = True
t.start()
return stop
return wrap
return outer_wrap
il peut être utilisé avec une quantité fixe de répétitions comme ci-dessus
@setInterval(1, 3)
def foo(a):
print(a)
foo('bar')
# Will print 'bar' 3 times with 1 second delays
ou peut être laissé courir jusqu'à ce qu'il reçoive un signal d'arrêt
import time
@setInterval(1)
def foo(a):
print(a)
stopper = foo('bar')
time.sleep(5)
stopper.set()
# It will stop here, after printing 'bar' 5 times.
4 réponses
votre solution me semble très bien.
il y a plusieurs façons de communiquer avec threads. Pour commander un thread à arrêter, vous pouvez utiliser threading.Event()
, qui a une méthode wait()
que vous pouvez utiliser au lieu de time.sleep()
.
stop_event = threading.Event()
...
stop_event.wait(1.)
if stop_event.isSet():
return
...
pour que votre thread sorte lorsque le programme est terminé, définissez son attribut daemon
à True
avant d'appeler start()
. Ceci s'applique aussi aux objets Timer()
car ils la sous-classe threading.Thread
. Voir http://docs.python.org/library/threading.html#threading.Thread.daemon
peut-être un peu plus simple est d'utiliser des appels récursifs au minuteur:
from threading import Timer
import atexit
class Repeat(object):
count = 0
@staticmethod
def repeat(rep, delay, func):
"repeat func rep times with a delay given in seconds"
if Repeat.count < rep:
# call func, you might want to add args here
func()
Repeat.count += 1
# setup a timer which calls repeat recursively
# again, if you need args for func, you have to add them here
timer = Timer(delay, Repeat.repeat, (rep, delay, func))
# register timer.cancel to stop the timer when you exit the interpreter
atexit.register(timer.cancel)
timer.start()
def foo():
print "bar"
Repeat.repeat(3,2,foo)
atexit
permet d'arrêter le signal avec CTRL-C.
peut-être que ce sont les équivalents setInterval les plus faciles en python:
import threading
def set_interval(func, sec):
def func_wrapper():
set_interval(func, sec)
func()
t = threading.Timer(sec, func_wrapper)
t.start()
return t
cet intervalle de classe
class ali:
def __init__(self):
self.sure = True;
def aliv(self,func,san):
print "ali naber";
self.setInterVal(func, san);
def setInterVal(self,func, san):
# istenilen saniye veya dakika aralığında program calışır.
def func_Calistir():
func(func,san); #calışıcak fonksiyon.
self.t = threading.Timer(san, func_Calistir)
self.t.start()
return self.t
a = ali();
a.setInterVal(a.aliv,5);