Frage

Hat Python hat eine ähnliche Funktion wie JavaScripts setInterval()?

Danke

Keine korrekte Lösung

Andere Tipps

Dies könnte den richtigen Code-Schnipsel, die Sie gesucht haben:

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

Nur halten sie schön und einfach.

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: Dieser Code ist nicht blockierenden

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"

Dies ist eine Version, wo Sie Start und Stopp konnte. Es wird nicht blockiert. Es gibt auch keine Panne als Laufzeitfehler nicht (wichtig für lange Ausführung mit sehr kurzem Intervall als Audio zum Beispiel) hinzugefügt

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()

Die Ausgabe ist:

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

Ändern Nailxx 's Antwort ein bisschen und Sie haben die Antwort!

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

Das sched Modul bietet diese Fähigkeiten für den allgemeinen Code Python. Doch wie seine Dokumentation schlägt vor, wenn Ihr Code multithreaded könnte es mehr Sinn machen, anstatt die threading.Timer Klasse zu verwenden.

Ich denke, das ist, was Sie nach:

#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()

Wenn Sie einen weiteren Eintrag in den Scheduler am Ende des sich wiederholenden Methode hinzufügen, wird es einfach weiter.

Einfache setInterval utils

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

Vor kurzem habe ich das gleiche Problem wie Sie. Und ich finde diese soluation:

1. Sie können die Bibliothek verwenden: threading.Time (diese Einführung haben oben)

2. Sie können die Bibliothek verwenden: sched (diese haben Einleitung oben zu)

3. Sie können die Bibliothek verwenden: Erweiterte Python Scheduler (empfohlen)

Das obige Verfahren hat recht es nicht für mich, da ich musste in der Lage sein, um das Intervall abzubrechen. Ich drehte mich um die Funktion in einer Klasse und kam mit dem Follow-up:

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()

Einige Antworten über diesen Anwendungen func_wrapper und threading.Timer zwar Arbeit, mit der Ausnahme, dass es jedes Mal ein Intervall einem neuen Thread laicht genannt wird, die Speicherprobleme verursacht.

Der Grund Beispiel unten ungefähr implementiert ein ähnlicher Mechanismus durch Intervall auf einem separaten Thread setzen. Es schläft im gegebenen Intervall. Vor dem Sprung in einen Code, sind hier einige der Einschränkungen, dass Sie sich bewusst sein müssen:

  1. JavaScript Single-Threaded ist, wenn so die Funktion innerhalb setInterval abgefeuert wird, nichts anderes zur gleichen Zeit arbeiten wird (Worker-Thread ohne, aber lassen Sie sich die allgemeinen Gebrauch Fall von setInterval sprechen. Daher Threading ist sicher. Aber hier in dieser Implementierung können Sie Rennbedingungen auftreten, es sei denn eine threading.rLock verwendet wird.

  2. Die Umsetzung unter Verwendungen time.sleep zu simulieren Intervalle, aber die Ausführungszeit von func Zugabe der Gesamtzeit für diesen Intervall kann größer sein als das, was Sie erwarten. Also je nach Anwendungsfällen, können Sie auf "sleep less" (minus Zeit für den Aufruf func genommen)

  3. ich nur ungefähr getestet diese, und Sie sollten auf jeden Fall nicht globale Variablen, die die Art und Weise verwenden, ich habe, fühlen Sie sich frei, es zu optimieren, so dass es in Ihrem System passt.


Genug geredet, hier ist der 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"

Erwartete Ausgabe:

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

Mein Python 3-Modul jsinterval.py wird hilfreich sein! Hier ist sie:

"""
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: Fixiert der Speicherverlust (durch @benjaminz spotted). Jetzt sind alle Fäden auf Ende gereinigt. Warum passiert das Leck? Es geschieht, weil die impliziten (oder sogar explizit) Referenzen. In meinem Fall TIMEOUTS und INTERVALS. Timeouts Selbstreinigung automatisch (nach diesem Patch), weil sie Funktion Wrapper verwenden, die die Funktion aufruft, und dann selbst tötet. Aber wie kommt es dazu? Objekte können nicht aus dem Speicher gelöscht werden, wenn alle Referenzen zu gelöscht oder gc Modul verwendet wird. Erklären: es gibt keinen Weg (in meinem Code), um unerwünschte Verweise auf Timeouts / Intervalle zu erstellen. Sie haben nur eine Referrer: die TIMEOUTS / INTERVALS dicts. Und wenn unterbrochen oder beendet (nur können Timeouts ununterbrochen beenden) sie löschen die einzige vorhandene Verweis auf sich selbst: ihre entsprechenden dict Element. Die Klassen sind perfekt gekapselt __all__ mit, so dass kein Platz für Speicherlecks.

Hier ist eine kleine Zeitdrift-Lösung, die einen Thread verwendet, um periodisch ein Ereignisobjekt signalisiert. Der Thread run () tut so gut wie nichts, während für ein Timeout warten; daher auch die geringe Zeitdrift.

# 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')

Die meisten Antworten über Schließ den Faden nicht ordnungsgemäß. Während Jupyter Notebook bemerkte ich, dass, wenn eine explizite Unterbrechung gesendet wurde, wurden die Fäden noch läuft und schlimmer noch, würde halten sie ab dem 1. Fadenlauf multipliziert, 2, 4 usw. unter Meine Methode auf die Antwort von @doom basiert aber sauber Griffe Interrupts durch eine Endlos-Schleife im Hauptthread läuft für SIGINT und SIGTERM Ereignisse

zu hören
  • Keine Drift
  • Cancelable
  • Griffe SIGINT und SIGTERM sehr gut
  • Doesnt machen einen neuen Thread für jeden Lauf

Sie können ferner Verbesserungen vorzuschlagen

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()

Dinge anders funktionieren in Python: Sie entweder sleep() müssen (wenn Sie den aktuellen Thread blockiert werden soll) oder einen neuen Thread starten. Siehe http://docs.python.org/library/threading.html

Python Dokumentation :

from threading import Timer

def hello():
    print "hello, world"

t = Timer(30.0, hello)
t.start() # after 30 seconds, "hello, world" will be printed
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top