É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 frappera Ctrl+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.
18
demandé sur Community 2011-03-03 13:28:24

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

10
répondu jd. 2011-03-03 15:21:37

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.

2
répondu Bernhard 2011-03-03 11:00:58

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
2
répondu stamat 2013-04-12 10:50:09

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);
0
répondu ali 2013-03-26 18:43:15