Python equivalente di setInterval ()?
-
01-10-2019 - |
Domanda
non Python ha una funzione simile a setInterval()
di JavaScript?
Grazie
Nessuna soluzione corretta
Altri suggerimenti
Questo potrebbe essere il frammento corretto che stavate cercando:
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
Basta tenerlo bello e semplice.
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: Questo codice è non bloccante
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"
Questa è una versione in cui si potrebbe iniziare e l'arresto. Non sta bloccando. Inoltre non c'è problema tecnico come errore di tempo di esecuzione non viene aggiunto (importante per l'esecuzione di molto tempo con intervallo molto breve come audio per esempio)
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()
L'uscita è:
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
Cambia Nailxx 's risposta un po' e si ha la risposta!
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
Il modulo sched
fornisce queste capacità per il codice Python generale. Tuttavia, come suggerisce la sua documentazione, se il codice è multithread potrebbe avere più senso utilizzare la classe threading.Timer
invece.
Credo che questo sia quello che stai dopo:
#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()
Se si aggiunge un'altra voce alla pianificazione, alla fine del metodo ripetere, sarà solo andare avanti.
Semplici 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
Di recente, ho lo stesso problema come te. E trovo questi soluation:
1. è possibile utilizzare la libreria: threading.Time (questo hanno introduzione sopra)
2. è possibile utilizzare la libreria: sched (questo hanno introduzione sopra troppo)
3. è possibile utilizzare la libreria: avanzata Python Scheduler (raccomandata)
Il metodo di cui sopra non ha abbastanza farlo per me, come avevo bisogno di essere in grado di annullare l'intervallo. Ho girato la funzione in una classe e si avvicinò con la seguente:
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()
Alcune risposte sopra che utilizza func_wrapper
e threading.Timer
anzi lavoro, tranne che genera un nuovo filo ogni volta che un intervallo è chiamato, che causa problemi di memoria.
L'esempio di base sotto circa implementato un meccanismo simile mettendo intervallo su un thread separato. Dorme al dato intervallo. Prima di saltare in codice, qui sono alcune delle limitazioni che è necessario essere a conoscenza di:
-
JavaScript è filettato unico, in modo che quando la funzione all'interno
setInterval
viene licenziato, non altro lavorerà allo stesso tempo (esclusi i thread di lavoro, ma parliamo caso d'uso generale dellasetInterval
. Pertanto, filettatura è sicuro. Ma qui, in questa implementazione, è possibile riscontrare condizioni di gara a meno che non si utilizza unthreading.rLock
. -
L'implementazione di seguito usi
time.sleep
a intervalli Simulare, ma aggiungendo il tempo di esecuzione dellafunc
, il tempo totale per questo intervallo può essere maggiore di quello che ci si aspetta. Quindi, a seconda dei casi d'uso, si consiglia di "sonno meno" (tempo meno preso per chiamarefunc
) -
Ho solo circa testato questo, e non si deve assolutamente utilizzare le variabili globali come ho fatto, sentitevi liberi di modificarlo in modo che si adatti nel vostro sistema.
Basta chiacchiere, ecco il codice:
# 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"
di uscita prevista:
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
Il mio Python 3 moduli jsinterval.py
sarà utile! Eccolo:
"""
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:
Risolto il problema di memoria (notato da @benjaminz). Ora tutti i fili sono puliti al momento finale. Perché succede questa perdita? Succede a causa dei riferimenti impliciti (o anche esplicita). Nel mio caso, TIMEOUTS
e INTERVALS
. Timeout auto-pulito automaticamente (dopo la patch) perché usano funzione wrapper che chiama la funzione e quindi di auto-uccide. Ma come avviene questo? Gli oggetti non possono essere cancellati dalla memoria a meno che non vengono cancellati anche tutti i riferimenti o viene utilizzato il modulo gc
. Spiegando: non c'è modo di creare (nel mio codice) riferimenti indesiderate al timeout / intervalli. Hanno un solo referente: i dicts TIMEOUTS
/ INTERVALS
. E, quando interrotti o finiti (solo timeout possono concretizzare ininterrotta) si elimina il riferimento soltanto esistente per se stessi: la loro corrispondente elemento dict. Classi sono perfettamente incapsulati utilizzando __all__
, quindi c'è spazio per perdite di memoria.
Ecco una soluzione deriva minimi che utilizza un filo per segnalare periodicamente un oggetto Event. run del thread () non fa quasi nulla in attesa di un timeout; da qui la bassa deriva tempo.
# 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 maggior parte delle risposte di cui sopra non spegnere il filo in modo corretto. Durante l'utilizzo Jupyter notebook Ho notato che quando un interrupt esplicito è stato inviato, i fili erano ancora in corso e peggio, avrebbero mantenere moltiplicando a partire da 1 filo conduttore, 2, 4, ecc Il mio metodo di seguito si basa sulla risposta da @doom ma in modo pulito maniglie interrupt eseguendo un ciclo infinito nel thread principale per ascoltare per la SIGINT e gli eventi SIGTERM
- Nessuna deriva
- annullabile
- Maniglie SIGINT e SIGTERM molto bene
- non rende un nuovo thread per ogni corsa
Sentitevi liberi di suggerire miglioramenti
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()
Le cose funzionano in modo diverso in Python: è necessario o sleep()
(se si desidera bloccare il thread corrente) o avviare un nuovo thread. Vedere http://docs.python.org/library/threading.html
from threading import Timer
def hello():
print "hello, world"
t = Timer(30.0, hello)
t.start() # after 30 seconds, "hello, world" will be printed