Question

Est-ce que Python a une fonction similaire à la setInterval() de JavaScript?

Merci

Pas de solution correcte

Autres conseils

Cela peut être l'extrait de code correct que vous recherchez:

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

Il suffit de le garder simple et agréable.

import threading

def setInterval(func,time):
    e = threading.Event()
    while not e.wait(time):
        func()

def foo():
    print "hello"

# using
setInterval(foo,5)

# output:
hello
hello
.
.
.

EDIT: Ce code est non-bloquant

import threading

class ThreadJob(threading.Thread):
    def __init__(self,callback,event,interval):
        '''runs the callback function after interval seconds

        :param callback:  callback function to invoke
        :param event: external event for controlling the update operation
        :param interval: time in seconds after which are required to fire the callback
        :type callback: function
        :type interval: int
        '''
        self.callback = callback
        self.event = event
        self.interval = interval
        super(ThreadJob,self).__init__()

    def run(self):
        while not self.event.wait(self.interval):
            self.callback()



event = threading.Event()

def foo():
    print "hello"

k = ThreadJob(foo,event,2)
k.start()

print "It is non-blocking"

Ceci est une version où vous pouvez démarrer et arrêter. Il ne bloque pas. Il n'y a pas non plus pépin comme une erreur de temps d'exécution n'est pas ajouté (important pour une longue exécution de temps avec un intervalle très court comme audio par exemple)

import time, threading

StartTime=time.time()

def action() :
    print('action ! -> time : {:.1f}s'.format(time.time()-StartTime))


class setInterval :
    def __init__(self,interval,action) :
        self.interval=interval
        self.action=action
        self.stopEvent=threading.Event()
        thread=threading.Thread(target=self.__setInterval)
        thread.start()

    def __setInterval(self) :
        nextTime=time.time()+self.interval
        while not self.stopEvent.wait(nextTime-time.time()) :
            nextTime+=self.interval
            self.action()

    def cancel(self) :
        self.stopEvent.set()

# start action every 0.6s
inter=setInterval(0.6,action)
print('just after setInterval -> time : {:.1f}s'.format(time.time()-StartTime))

# will stop interval in 5s
t=threading.Timer(5,inter.cancel)
t.start()

sortie est la suivante:

just after setInterval -> time : 0.0s
action ! -> time : 0.6s
action ! -> time : 1.2s
action ! -> time : 1.8s
action ! -> time : 2.4s
action ! -> time : 3.0s
action ! -> time : 3.6s
action ! -> time : 4.2s
action ! -> time : 4.8s

Modifier Nailxx de "réponse un peu et vous avez obtenu la réponse!

from threading import Timer

def hello():
    print "hello, world"
    Timer(30.0, hello).start()

Timer(30.0, hello).start() # after 30 seconds, "hello, world" will be printed

Le module sched offre ces capacités pour le code général Python. Cependant, comme sa documentation indique, si votre code est multithread, il serait plus logique d'utiliser la classe à la place de threading.Timer.

Je pense que c'est ce que vous êtes après:

#timertest.py
import sched, time
def dostuff():
  print "stuff is being done!"
  s.enter(3, 1, dostuff, ())

s = sched.scheduler(time.time, time.sleep)
s.enter(3, 1, dostuff, ())
s.run()

Si vous ajoutez une entrée au programmateur à la fin de la méthode à répéter, il va juste continuer.

Simple utils setInterval

from threading import Timer

def setInterval(timer, task):
    isStop = task()
    if not isStop:
        Timer(timer, setInterval, [timer, task]).start()

def hello():
    print "do something"
    return False # return True if you want to stop

if __name__ == "__main__":
    setInterval(2.0, hello) # every 2 seconds, "do something" will be printed

Récemment, j'ai le même problème que vous. Et je trouve ces soluation:

1. vous pouvez utiliser la bibliothèque: threading.Time (cela a l'introduction ci-dessus)

2. vous pouvez utiliser la bibliothèque: sched (cette introduction ci-dessus ont aussi)

3. vous pouvez utiliser la bibliothèque: (Recommander) avancée Python Scheduler

La méthode ci-dessus n'a pas tout à fait le faire pour moi que je devais être en mesure d'annuler l'intervalle. Je me suis tourné la fonction dans une classe et est venu avec ce qui suit:

class setInterval():
    def __init__(self, func, sec):
        def func_wrapper():
            self.t = threading.Timer(sec, func_wrapper)
            self.t.start()
            func()
        self.t = threading.Timer(sec, func_wrapper)
        self.t.start()

    def cancel(self):
        self.t.cancel()

Quelques réponses ci-dessus que les utilisations func_wrapper et threading.Timer fait le travail, sauf qu'il engendre un nouveau thread à chaque fois un intervalle est appelé, ce qui est à l'origine des problèmes de mémoire.

L'exemple de base ci-dessous grossièrement mis en place un mécanisme similaire en mettant l'intervalle sur un fil séparé. Il dort à l'intervalle donné. Avant de sauter dans le code, voici quelques-unes des limites que vous devez être au courant:

  1. JavaScript est seul thread, donc lorsque la fonction à l'intérieur setInterval est tiré, rien d'autre va travailler en même temps (hors thread de travail, mais nous allons parler usage général cas de setInterval. Par conséquent, le filetage est sûr. Mais dans cette mise en œuvre, vous pouvez rencontrer des conditions de course à moins d'utiliser un threading.rLock.

  2. La mise en œuvre ci-dessous des utilisations time.sleep à intervalles Simuler, mais en ajoutant le temps d'exécution de func, le temps total pour cette intervalle peut être supérieur à ce que vous attendez. Ainsi, selon les cas d'utilisation, vous pouvez « dormir moins » (temps moins pris pour appeler func)

  3. Je ne à peu près testé, et vous ne devriez certainement pas utiliser des variables globales comme moi, ne hésitez pas à ruser pour qu'il se glisse dans votre système.


Assez parlé, voici le code:

# Python 2.7
import threading
import time


class Interval(object):
    def __init__(self):
        self.daemon_alive = True
        self.thread = None # keep a reference to the thread so that we can "join"

    def ticktock(self, interval, func):
        while self.daemon_alive:
            time.sleep(interval)
            func()

num = 0
def print_num():
    global num
    num += 1
    print 'num + 1 = ', num

def print_negative_num():
    global num
    print '-num = ', num * -1

intervals = {} # keep track of intervals
g_id_counter = 0 # roughly generate ids for intervals

def set_interval(interval, func):
    global g_id_counter

    interval_obj = Interval()
    # Put this interval on a new thread
    t = threading.Thread(target=interval_obj.ticktock, args=(interval, func))
    t.setDaemon(True)
    interval_obj.thread = t
    t.start()

    # Register this interval so that we can clear it later
    # using roughly generated id
    interval_id = g_id_counter
    g_id_counter += 1
    intervals[interval_id] = interval_obj

    # return interval id like it does in JavaScript
    return interval_id

def clear_interval(interval_id):
    # terminate this interval's while loop
    intervals[interval_id].daemon_alive = False
    # kill the thread
    intervals[interval_id].thread.join()
    # pop out the interval from registry for reusing
    intervals.pop(interval_id)

if __name__ == '__main__':
    num_interval = set_interval(1, print_num)
    neg_interval = set_interval(3, print_negative_num)

    time.sleep(10) # Sleep 10 seconds on main thread to let interval run
    clear_interval(num_interval)
    clear_interval(neg_interval)
    print "- Are intervals all cleared?"
    time.sleep(3) # check if both intervals are stopped (not printing)
    print "- Yup, time to get beers"

Sortie prévue:

num + 1 =  1
num + 1 =  2
-num =  -2
 num + 1 =  3
num + 1 =  4
num + 1 =  5
-num =  -5
num + 1 =  6
num + 1 =  7
num + 1 =  8
-num =  -8
num + 1 =  9
num + 1 =  10
-num =  -10
Are intervals all cleared?
Yup, time to get beers

Mon Python 3 Module jsinterval.py sera utile! Ici, il est:

"""
Threaded intervals and timeouts from JavaScript
"""

import threading, sys

__all__ =  ['TIMEOUTS', 'INTERVALS', 'setInterval', 'clearInterval', 'setTimeout', 'clearTimeout']

TIMEOUTS  = {}
INTERVALS = {}

last_timeout_id  = 0
last_interval_id = 0

class Timeout:
    """Class for all timeouts."""
    def __init__(self, func, timeout):
        global last_timeout_id
        last_timeout_id += 1
        self.timeout_id = last_timeout_id
        TIMEOUTS[str(self.timeout_id)] = self
        self.func = func
        self.timeout = timeout
        self.threadname = 'Timeout #%s' %self.timeout_id

    def run(self):
        func = self.func
        delx = self.__del__
        def func_wrapper():
            func()
            delx()
        self.t = threading.Timer(self.timeout/1000, func_wrapper)
        self.t.name = self.threadname
        self.t.start()

    def __repr__(self):
        return '<JS Timeout set for %s seconds, launching function %s on timeout reached>' %(self.timeout, repr(self.func))

    def __del__(self):
        self.t.cancel()

class Interval:
    """Class for all intervals."""
    def __init__(self, func, interval):
        global last_interval_id
        self.interval_id = last_interval_id
        INTERVALS[str(self.interval_id)] = self
        last_interval_id += 1
        self.func = func
        self.interval = interval
        self.threadname = 'Interval #%s' %self.interval_id

    def run(self):
        func = self.func
        interval = self.interval
        def func_wrapper():
            timeout = Timeout(func_wrapper, interval)
            self.timeout = timeout
            timeout.run()
            func()
        self.t = threading.Timer(self.interval/1000, func_wrapper)
        self.t.name = self.threadname
        self.t.run()

    def __repr__(self):
        return '<JS Interval, repeating function %s with interval %s>' %(repr(self.func), self.interval)

    def __del__(self):
        self.timeout.__del__()

def setInterval(func, interval):
    """
    Create a JS Interval: func is the function to repeat, interval is the interval (in ms)
    of executing the function.
    """
    temp = Interval(func, interval)
    temp.run()
    idx = int(temp.interval_id)
    del temp
    return idx


def clearInterval(interval_id):
    try:
        INTERVALS[str(interval_id)].__del__()
        del INTERVALS[str(interval_id)]
    except KeyError:
        sys.stderr.write('No such interval "Interval #%s"\n' %interval_id)

def setTimeout(func, timeout):
    """
    Create a JS Timeout: func is the function to timeout, timeout is the timeout (in ms)
    of executing the function.
    """
    temp = Timeout(func, timeout)
    temp.run()
    idx = int(temp.timeout_id)
    del temp
    return idx


def clearTimeout(timeout_id):
    try:
        TIMEOUTS[str(timeout_id)].__del__()
        del TIMEOUTS[str(timeout_id)]
    except KeyError:
        sys.stderr.write('No such timeout "Timeout #%s"\n' %timeout_id)

CODE EDIT: Correction de la fuite de mémoire (repéré par @benjaminz). Maintenant, toutes les discussions sont nettoyés à la fin. Pourquoi cette fuite se produit? Il arrive que des références implicites (ou même explicite). Dans mon cas, TIMEOUTS et INTERVALS. Temporisations automatiquement l'auto-propre (après ce patch) car ils utilisent wrapper fonction qui appelle la fonction et l'auto-tue. Mais comment cela se produit-il? Les objets ne peuvent être effacés de la mémoire à moins que toutes les références sont également supprimées ou un module gc est utilisé. Expliquer: il n'y a aucun moyen de créer (dans mon code) références indésirables à Timeouts / intervalles. Ils ont qu'un seul referrer: les dicts TIMEOUTS / INTERVALS. Et, en cas d'interruption ou finis (seulement les délais d'attente peuvent terminer sans interruption) ils suppriment la référence existante à eux-mêmes: leur élément dict correspondant. Les classes sont parfaitement encapsulés en utilisant __all__, donc pas de place pour les fuites de mémoire.

Voici une solution de faible dérive temporelle qui utilise un fil pour signaler périodiquement un objet de l'événement. La course du fil () ne fait presque rien en attendant un délai d'attente; d'où la faible dérive du temps.

# Example of low drift (time) periodic execution of a function.
import threading
import time

# Thread that sets 'flag' after 'timeout'
class timerThread (threading.Thread):

    def __init__(self , timeout , flag):
        threading.Thread.__init__(self)
        self.timeout = timeout
        self.stopFlag = False
        self.event = threading.Event()
        self.flag = flag

    # Low drift run(); there is only the 'if'
    # and 'set' methods between waits.
    def run(self):
        while not self.event.wait(self.timeout):
            if self.stopFlag:
                break
            self.flag.set()

    def stop(self):
        stopFlag = True
        self.event.set()

# Data.
printCnt = 0

# Flag to print.
printFlag = threading.Event()

# Create and start the timer thread.
printThread = timerThread(3 , printFlag)
printThread.start()

# Loop to wait for flag and print time.
while True:

    global printCnt

    # Wait for flag.
    printFlag.wait()
    # Flag must be manually cleared.
    printFlag.clear()
    print(time.time())
    printCnt += 1
    if printCnt == 3:
        break;

# Stop the thread and exit.
printThread.stop()
printThread.join()
print('Done')

La plupart des réponses ci-dessus n'arrêtez pas le fil correctement. Tout en utilisant ordinateur portable Jupyter j'ai remarqué que lorsqu'une interruption explicite a été envoyé, les fils étaient encore en cours d'exécution et pire, ils garderait la multiplication à partir de 1 course de fil, 2, 4, etc. Ma méthode ci-dessous est basée sur la réponse par @doom mais proprement poignées interruptions en exécutant une boucle infinie dans le fil principal en écoute pour SIGINT et événements SIGTERM

  • Pas de dérive
  • annulable
  • Poignées SIGINT et SIGTERM très bien
  • Doesnt faire un nouveau thread pour chaque course

Ne hésitez pas à suggérer des améliorations

import time
import threading
import signal

# Record the time for the purposes of demonstration 
start_time=time.time()

class ProgramKilled(Exception):
    """
    An instance of this custom exception class will be thrown everytime we get an SIGTERM or SIGINT
    """
    pass

# Raise the custom exception whenever SIGINT or SIGTERM is triggered
def signal_handler(signum, frame):
    raise ProgramKilled

# This function serves as the callback triggered on every run of our IntervalThread
def action() :
    print('action ! -> time : {:.1f}s'.format(time.time()-start_time))

# https://stackoverflow.com/questions/2697039/python-equivalent-of-setinterval
class IntervalThread(threading.Thread) :
    def __init__(self,interval,action, *args, **kwargs) :
        super(IntervalThread, self).__init__()
        self.interval=interval
        self.action=action
        self.stopEvent=threading.Event()
        self.start()

    def run(self) :
        nextTime=time.time()+self.interval
        while not self.stopEvent.wait(nextTime-time.time()) :
            nextTime+=self.interval
            self.action()

    def cancel(self) :
        self.stopEvent.set()

def main():

    # Handle SIGINT and SIFTERM with the help of the callback function
    signal.signal(signal.SIGTERM, signal_handler)
    signal.signal(signal.SIGINT, signal_handler)
    # start action every 1s
    inter=IntervalThread(1,action)
    print('just after setInterval -> time : {:.1f}s'.format(time.time()-start_time))

    # will stop interval in 500s
    t=threading.Timer(500,inter.cancel)
    t.start()

    # https://www.g-loaded.eu/2016/11/24/how-to-terminate-running-python-threads-using-signals/
    while True:
        try:
            time.sleep(1)
        except ProgramKilled:
            print("Program killed: running cleanup code")
            inter.cancel()
            break

if __name__ == "__main__":
    main()

Les choses fonctionnent différemment en Python: vous devez soit sleep() (si vous voulez bloquer le thread en cours) ou lancer un nouveau fil. Voir http://docs.python.org/library/threading.html

De Python Documentation :

from threading import Timer

def hello():
    print "hello, world"

t = Timer(30.0, hello)
t.start() # after 30 seconds, "hello, world" will be printed
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top