Эквивалент Python для setInterval ()? - PullRequest
31 голосов
/ 23 апреля 2010

Имеет ли Python функцию, аналогичную setInterval()?

в JavaScript

Спасибо

Ответы [ 15 ]

28 голосов
/ 26 декабря 2012

Это может быть правильный фрагмент, который вы искали:

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
8 голосов
/ 09 февраля 2018

Это версия, где вы можете запускать и останавливать. Это не блокировка. Также нет сбоев, так как ошибка времени выполнения не добавляется (важно для долгого выполнения с очень коротким интервалом, как, например, для звука)

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

Вывод:

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
8 голосов
/ 27 июня 2015

Просто держите это красиво и просто.

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
.
.
.

РЕДАКТИРОВАТЬ: этот код является неблокирующим

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"
5 голосов
/ 03 ноября 2013

Изменение Nailxx ответь немного, и ты получил ответ!

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
5 голосов
/ 23 апреля 2010

Модуль sched предоставляет эти возможности для общего кода Python. Однако, как следует из документации, если ваш код является многопоточным, возможно, имеет смысл использовать класс threading.Timer.

3 голосов
/ 04 января 2012

Я думаю, это то, что вам нужно:

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

Если вы добавите еще одну запись в планировщик в конце повторяющегося метода, он просто продолжит работу.

1 голос
/ 07 января 2019

Простые утилиты 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
0 голосов
/ 26 февраля 2019

Большинство ответов выше не закрывают тему должным образом. При использовании ноутбука Jupyter я заметил, что при отправке явного прерывания потоки все еще работали и хуже, они продолжали умножаться, начиная с 1 потока, 2, 4 и т. Д. Мой метод ниже основан на ответе @doom, но чисто обрабатывает прерывания, выполняя бесконечный цикл в главном потоке для прослушивания событий SIGINT и SIGTERM

  • Нет дрейфа
  • аннулированию
  • Очень хорошо справляется с SIGINT и SIGTERM
  • Не создает новый поток для каждого запуска

Не стесняйтесь предлагать улучшения

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

# /2278117/ekvivalent-python-dlya-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()
0 голосов
/ 20 ноября 2017

Вот решение с малым временем дрейфа, которое использует поток для периодической сигнализации объекта Event.Поток run () почти ничего не делает, ожидая таймаута;отсюда и небольшой дрейф времени.

# 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')
0 голосов
/ 16 июля 2017

Мой модуль Python 3 jsinterval.py будет полезен! Вот оно:

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

РЕДАКТИРОВАНИЕ КОДА: Исправлена ​​утечка памяти (замечена @benjaminz). Теперь ВСЕ темы очищены по окончании. Почему происходит эта утечка? Это происходит из-за неявных (или даже явных) ссылок. В моем случае TIMEOUTS и INTERVALS. Тайм-ауты автоматически очищаются (после этого патча), потому что они используют функцию-обертку, которая вызывает функцию, а затем самоуничтожается. Но как это происходит? Объекты не могут быть удалены из памяти, если не удалены все ссылки или не используется модуль gc. Объяснение: нет способа создать (в моем коде) нежелательные ссылки на тайм-ауты / интервалы. У них есть только ОДИН реферер: TIMEOUTS / INTERVALS dicts. И, когда прервано или закончено (только таймауты могут закончить непрерывно), они удаляют единственную существующую ссылку на себя: их соответствующий элемент dict. Классы идеально инкапсулированы с использованием __all__, поэтому нет места для утечек памяти.

...