Эквивалент setInterval в Python - PullRequest
19 голосов
/ 03 марта 2011

Я недавно опубликовал вопрос о том, как отложить выполнение функции в Python (что-то вроде Javascript setTimeout), и это оказалось простой задачей с использованием threading.Timer (хорошоЭто просто, если функция не разделяет состояние с другим кодом, но это может создать проблемы в любой среде, управляемой событиями.Для тех, кто не знаком с 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 ]

11 голосов
/ 03 марта 2011

Ваше решение выглядит хорошо для меня.

Существует несколько способов общения с потоками. Чтобы приказать потоку остановиться, вы можете использовать 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#threading.Thread.daemon

2 голосов
/ 26 декабря 2012

Возможно, это самый простой эквивалент 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
2 голосов
/ 03 марта 2011

Возможно, немного проще использовать рекурсивные вызовы к Таймеру:

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.

0 голосов
/ 26 марта 2013

Интервал этого класса

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);
...