Вопрос

Есть ли у Python функция, похожая на JavaScript setInterval()?

Спасибо

Нет правильного решения

Другие советы

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

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

Просто держите его приятно и просто.

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"

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

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

Изменять Icaxx.Ответь немного, и вы получили ответ!

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

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

Я думаю, что это то, что вы после:

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

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

Простое 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

Недавно у меня такая же проблема, как вы. И я нахожу эти валюты:

1. Вы можете использовать библиотеку: Threading.Time.(Это имеет введение выше)

2. Вы можете использовать библиотеку: Снимитесь(Это имеет введение выше)

3. Вы можете использовать библиотеку: Расширенный планировщик Python(Рекомендовать)

Вышеуказанный метод не совсем не делал для меня, так как мне нужно было уметь отменить интервал. Я включал функцию в класс и придумал следующее:

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

Некоторые ответы выше, которые используют func_wrapper а также threading.Timer Действительно работа, за исключением того, что он вызывает новую нить каждый раз, когда называется интервал, который вызывает проблемы с памятью.

Основной пример ниже грубо внедрил аналогичный механизм путем положения интервала на отдельный поток. Он спит по данному интервалу. Перед прыжками в код, вот некоторые ограничения, которые вам нужно знать:

  1. JavaScript - это отдельная резьба, поэтому, когда функция внутри setInterval уволен, ничто другое не будет работать одновременно (исключая нить работника, но давайте поговорим общий случай setInterval. Отказ Поэтому резьба безопасна. Но здесь, в этой реализации, вы можете столкнуться с условиями гонок, если не используете threading.rLock.

  2. Внедрение ниже использования time.sleep имитировать интервалы, но добавление времени выполнения func, общее время для этого интервал может быть больше, чем то, что вы ожидаете. Таким образом, в зависимости от случаев использования вы можете «меньше» (меньшее время, необходимое для звонков func)

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


Достаточно говорить, вот код:

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

Ожидаемый выход:

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

Мой модуль 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 диктует.И, когда прерывается или завершается (только тайм-ауты могут завершаться непрерывно), они удаляют единственную существующую ссылку на себя:их соответствующий элемент dict.Классы идеально инкапсулируются с помощью __all__, так что нет места для утечек памяти.

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

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

Большинство ответов выше не закрывают нити правильно. При использовании ноутбука 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))

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

Вещи работают по-разному в Python: вам нужно либо sleep() (Если вы хотите заблокировать текущий поток) или запустите новый поток. Видеть http://docs.ython.org/library/thhreading.html.

От Документация Python:

from threading import Timer

def hello():
    print "hello, world"

t = Timer(30.0, hello)
t.start() # after 30 seconds, "hello, world" will be printed
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top