Эквивалент setInterval в Python
Недавно я опубликовал вопрос о том, как отложить выполнение функции в Python (что-то вроде Javascript setTimeout
) и это оказывается простой задачей, используя threading.Timer
(ну, просто, если функция не разделяет состояние с другим кодом, но это может создать проблемы в любой управляемой событиями среде).
Сейчас я пытаюсь сделать лучше и подражать setInterval
, Для тех, кто не знаком с Javascript, setInterval
позволяет повторять вызов функции каждые x секунд, не блокируя выполнение другого кода. Я создал этот пример декоратора:
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
использоваться следующим образом
@setInterval(1, 3)
def foo(a):
print(a)
foo('bar')
# Will print 'bar' 3 times with 1 second delays
и мне кажется, что он работает нормально. Моя проблема в том что
- это кажется слишком сложным, и я боюсь, что, возможно, пропустил более простой / лучший механизм
- декоратор может быть вызван без второго параметра, и в этом случае он будет продолжаться вечно. Когда я говорю навсегда, я имею в виду навсегда - даже звоню
sys.exit()
из основного потока не остановит его и не ударитCtrl+c
, Единственный способ остановить это - убить процесс Python извне. Я хотел бы иметь возможность отправить сигнал из основного потока, который остановит обратный вызов. Но я новичок с нитями - как я могу общаться между ними?
РЕДАКТИРОВАТЬ В случае, если кто-то задается вопросом, это финальная версия декоратора, благодаря помощи 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
Может использоваться с фиксированным количеством повторений, как указано выше.
@setInterval(1, 3)
def foo(a):
print(a)
foo('bar')
# Will print 'bar' 3 times with 1 second delays
или может быть запущен, пока не получит сигнал остановки
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 ответа
Ваше решение выглядит хорошо для меня.
Есть несколько способов общения с потоками. Чтобы заказать остановку потока, вы можете использовать threading.Event()
, который имеет wait()
метод, который вы можете использовать вместо time.sleep()
,
stop_event = threading.Event()
...
stop_event.wait(1.)
if stop_event.isSet():
return
...
Чтобы ваш поток мог выйти после завершения программы, установите его daemon
приписывать True
перед звонком start()
, Это относится к Timer()
объекты, а также потому, что они подкласс threading.Thread
, См. http://docs.python.org/library/threading.html.
Может быть, это самый простой эквивалент setInterval в 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
Может быть, немного проще использовать рекурсивные вызовы Timer:
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
позволяет сигнализировать об остановке с помощью CTRL-C.
Этот класс Интервал
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);