2010-04-23 15 views
20

Czy Python ma funkcję podobną do JavaScript setInterval()?Python Równoważnik setInterval()?

Dzięki

+0

[oto 'setInterval() 'dekorator] (http://stackoverflow.com/a/16368571/4279) lub [bez wątków używających Tkintera, Gtk, Twisted pętli zdarzeń] (http://stackoverflow.com/a/14040516/4279) – jfs

+0

[' call_repeatedly (interwał, funkcja, * args) '] (http://stackoverflow.com/a/22498708/4279) – jfs

Odpowiedz

5

Moduł sched zapewnia te zdolności do ogólnego kodu Pythona. Jednak, jak sugeruje jego dokumentacja, jeśli twój kod jest wielowątkowy, może być bardziej sensowne używanie klasy threading.Timer.

+0

Dobrze, zapomniałem o tym! +1 – EMP

-1

Rzeczy działają inaczej w Pythonie: musisz albo sleep() (jeśli chcesz zablokować bieżący wątek) lub rozpocząć nowy wątek. Zobacz http://docs.python.org/library/threading.html

+2

Używanie wątków + sen nie jest najlepszym sposobem na wdrożenie tego. Różne harmonogramy i pętle zdarzeń, a nawet elementy wygody w module wątków tworzą lepsze rozwiązania. –

-1

Od 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 
+0

i jak ustawić interval w python? – zjm1126

+1

?? Czy nie jest to oczywiste z przykładu? 'Timer (your_interval, your_function_to_call) .start()' – nkrkv

+4

ale setinterval nie jest ustalony, setinterval działa wiecznie – zjm1126

3

myślę, że to jest to, co jesteś po:

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

Jeśli dodać kolejny wpis do terminarza na końcu metody powtarzając go Po prostu idź dalej.

+1

Pierwszym argumentem metody enter() jest opóźnienie, przy okazji. Ten przykład śpi przez 3 sekundy. – visum

+0

Przykłady 'apscheduler' dla długoterminowej dokładności [tutaj] (https://stackoverflow.com/q/22715086/2192488). –

+0

Zamiast tego używaj ['apscheduler'] (https://apscheduler.readthedocs.io/en/latest/modules/triggers/interval.html#module-apscheduler.triggers.interval) z' (time.time, time.sleep, timezone = 'UTC') ', aby uniknąć błędów indukowanych czasem letnim (DST). –

25

To może być poprawny fragment szukałeś:

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 
+1

Czy można w tym celu wywołać '' 't.cancel()' ''? Wydaje się to ignorować. –

+0

Oto trochę kodu Python3, aby pokazać, co mam na myśli: http://pastebin.ubuntu.com/24304218/ –

+2

ta metoda nadal będzie stosunkowo szybko dryfować, szczególnie jeśli czasy oczekiwania są poniżej jednej sekundy. Czy istnieje jakaś dobra metoda otrzymywania sygnału (lub wywoływania funkcji) na podstawie czasu podobnego do czasu systemowego lub RTC lub podobnego? Coś, co może nie gromadzić dryfu na dłuższą metę – assassinatorr

4

Zmień Nailxx „s odpowiedź trochę i masz odpowiedź!

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 
+0

Ładne inicjowanie i uruchamianie obiektu 'Timer' w jednym wierszu! –

0

Niedawno mam taki sam problem jak Ty. I znajdę te soluation:

1. Można użyć biblioteki: threading.Time (ten wstęp mają powyżej)

2. można użyć biblioteki: sched (to mieć wprowadzenie powyżej zbyt)

3. można korzystać z biblioteki: Advanced Python Scheduler (polecam)

4

Wystarczy zachować ładne i proste, nie wiem, dlaczego wszystko odpowiedzi robią rzeczy tyle złożona:

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: Ten kod jest non-blocking

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" 
+2

Ta setInterval jest blokowana i kod po wywołaniu setInterval (foo, 5) nie wywołałby – saman

0

Powyższa metoda nie całkiem to zrobić dla mnie, jako potrzebne, aby móc aby anulować interwał. Odwróciłem funkcji w klasie i wpadł na następujące elementy:

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

Niektóre odpowiedzi powyżej, który używa func_wrapper i threading.Timer rzeczywiście pracy, z wyjątkiem, że spawns nowego wątku za każdym razem przerwa jest wywoływana, który jest przyczyną pamięci problemy.

Podstawowy przykład poniżej około zaimplementował podobny mechanizm, umieszczając przedział na osobnym wątku. Śpi w określonym przedziale czasowym.Przed skokiem do kodu, oto niektóre z ograniczeń, które trzeba mieć świadomość:

  1. JavaScript jest pojedynczym gwintowane, więc gdy funkcja wewnątrz setInterval jest zwolniony, nic innego nie będzie pracować w tym samym czasie (bez wątku roboczego, ale pomówmy ogólny przypadek zastosowania setInterval. w związku z tym, gwintowania jest bezpieczne. ale tu, w tej realizacji, mogą wystąpić warunki wyścigu, chyba że przy użyciu threading.rLock.

  2. realizacja poniżej wykorzystuje time.sleep symulować interwały, ale dodając czas wykonania func, łączny czas dla tego interwał może być większy niż oczekiwany. Tak więc w zależności od przypadków użycia, może chcesz „spać mniej” (minus czas potrzebny do wywołania func)

  3. ja tylko grubsza przetestowane i nie powinny zdecydowanie wykorzystywać zmienne globalne tak zrobiłem, nie krępuj dostosować go tak, aby pasował do twojego systemu.


Dość gadania, oto kod:

# 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" 

oczekiwany wynik:

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 
0

My Python 3 moduł jsinterval.py będą pomocne! Tutaj jest on:

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

KOD Edycja: stałej wyciek pamięci (zauważony przez @benjaminz). Teraz WSZYSTKIE wątki są czyszczone po zakończeniu. Dlaczego ten wyciek ma miejsce? Dzieje się tak z powodu niejawnych (lub nawet wyraźnych) odniesień. W moim przypadku: TIMEOUTS i INTERVALS. Czasy automatycznie oczyszczają się (po tej łatce), ponieważ używają funkcji owijającej funkcję, a następnie zabijającej. Ale jak to się dzieje? Obiekty nie mogą być usunięte z pamięci, chyba że wszystkie odwołania zostaną usunięte lub użyty zostanie moduł gc. Wyjaśnienie: nie ma sposobu, aby utworzyć (w moim kodzie) niechciane odniesienia do limitów czasu/przerw. Mają tylko JEDNA stronę odsyłającą: dyktuje: TIMEOUTS/INTERVALS. A gdy zostaną przerwane lub zakończone (tylko limity czasu mogą się kończyć bez przerwy), usuwają jedyne istniejące odniesienie do siebie: odpowiadający im element dyktujący. Klasy są idealnie enkapsulowane przy użyciu __all__, więc nie ma miejsca na wycieki pamięci.

0

Oto niski czas dryfowania, który używa wątku do okresowego sygnalizowania obiektu Event. Bieg nici() prawie nic podczas oczekiwania na timeout; stąd niski czas dryfowania.

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

Jest to wersja, w której można rozpocząć i zatrzymać. To nie jest blokowanie. Nie ma też usterki jako błąd czasu wykonania nie jest dodawana (ważne przez długi czas realizacji z bardzo krótkim odstępie jako audio na przykład)

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

wyjścia:

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