Який найкращий спосіб багаторазово виконувати функцію кожні х секунд?


283

Я хочу неодноразово виконувати функцію в Python кожні 60 секунд назавжди (як і NSTimer у Objective C). Цей код буде виконуватись як демон і фактично схожий на виклик сценарію python щохвилини за допомогою крона, але не вимагаючи, щоб його встановлював користувач.

У цьому питанні про хрон, реалізований у Python , з'являється рішення, що ефективно просто спати () протягом x секунд. Мені не потрібна така розширена функціональність, тому, можливо, щось подібне спрацювало б

while True:
    # Code executed here
    time.sleep(60)

Чи є передбачувані проблеми з цим кодом?


83
Педантична точка, але може бути критичною, ваш код вище коду не виконується кожні 60 секунд, він ставить 60-секундний розрив між стратами. Це відбувається лише кожні 60 секунд, якщо виконаний код зовсім не займає часу.
Саймон

4
також time.sleep(60)може повернутися і раніше, і пізніше
jfs

5
Мені все ще цікаво: Чи є передбачувані проблеми з цим кодом?
Банан

1
"Передбачувана проблема" полягає в тому, що ви не можете очікувати 60 ітерацій на годину, просто використовуючи time.sleep (60). Отже, якщо ви додаєте один елемент за ітерацією та зберігаєте список заданої довжини ... середнє значення цього списку не буде представляти собою послідовний "період" часу; тож такі функції, як "ковзаюча середня величина", можуть посилатися на занадто старі точки даних, які спотворюватимуть ваші показники.
litepresence

2
@Banana Так, ви можете очікувати будь-яких проблем, викликаних тим, що ваш сценарій не виконується ТОЧНО кожні 60 секунд. Наприклад. Я почав робити щось подібне, щоб розділити відеопотоки та upload'em, і в кінцевому підсумку отримую потоки на 5-10 ~ секунди довше, оскільки медіа-черга буферизується, коли я обробляю дані всередині циклу. Це залежить від ваших даних. Якщо ця функція є якоюсь простою сторожовою стороною, яка попереджає вас, наприклад, коли ваш диск заповнений, у вас із цим взагалі не повинно виникнути проблем. Якщо ви перевіряєте попередження про атомну електростанцію, то у вас може виникнути місто повністю підірваний х
DGoiko

Відповіді:


229

Якщо ваша програма не має цикл подій вже, використовуйте SCHED модуль, який реалізує планувальник подій загального призначення.

import sched, time
s = sched.scheduler(time.time, time.sleep)
def do_something(sc): 
    print("Doing stuff...")
    # do your stuff
    s.enter(60, 1, do_something, (sc,))

s.enter(60, 1, do_something, (s,))
s.run()

Якщо ви вже використовуєте бібліотеку циклу події , як asyncio, trio, tkinter, PyQt5, gobject, kivy, і багато інших - просто запланувати завдання з допомогою методів існуючої бібліотеки циклу обробки подій, замість.


16
Модуль планування призначений для виконання функцій планування через деякий час, як ви використовуєте його для повторення виклику функції кожні х секунд, не використовуючи time.sleep ()?
Baishampayan Ghose

2
@Baishampayan: Просто заплануйте новий пробіг.
nosklo

3
Тоді apscheduler на пакунках.python.org/ APScheduler також повинен згадати в цьому пункті.
Даніель Ф

6
Примітка: ця версія може занести. Ви можете використовувати, enterabs()щоб уникнути цього. Ось не-дрейфуюча версія для порівняння .
jfs

8
@JavaSa: тому що "робити свої речі" не миттєво і time.sleepтут можуть накопичуватися помилки . "виконувати кожні X секунд" та "виконувати із затримкою ~ X секунд повторно" - це не те саме. Дивіться також цей коментар
jfs

180

Заблокуйте часовий цикл на системному годиннику так:

import time
starttime = time.time()
while True:
    print "tick"
    time.sleep(60.0 - ((time.time() - starttime) % 60.0))

22
+1. Ваша twistedвідповідь - це єдині відповіді, які виконують функцію кожні xсекунди. Решта виконують функцію із затримкою xсекунд після кожного дзвінка.
jfs

13
Якщо вам де додати якийсь код до цього, який зайняв би більше однієї секунди ... Це би викинуло час і почало відставати .. Прийнята відповідь у цьому випадку правильна ... Будь-хто може зафіксувати просту команду друку і нехай це запускається щосекунди без зволікань ...
Злий 84

5
Я віддаю перевагу from time import time, sleepз екзистенціальних наслідків;)
Will

14
Працює фантастично. Немає необхідності віднімати ваші, starttimeякщо ви почнете з синхронізації до певного часу: time.sleep(60 - time.time() % 60)для мене добре працює. Я використовував його як time.sleep(1200 - time.time() % 1200)і він дає мені журнали на :00 :20 :40, точно так, як я хотів.
TemporalWolf

2
@AntonSchigur, щоб уникнути дрейфу після декількох ітерацій. Індивідуум ітерація може початися трохи раніше або пізніше в залежності від того sleep(), timer()точності і скільки часу потрібно , щоб виконати тіло циклу , але в середньому ітерацій завжди відбуваються на кордонах інтервалів (навіть якщо деякі з них пропущені): while keep_doing_it(): sleep(interval - timer() % interval). Порівняйте його з тим, while keep_doing_it(): sleep(interval)де помилки можуть накопичуватися після кількох ітерацій.
jfs

71

Ви можете розглянути Twisted, який є мережевою бібліотекою Python, що реалізує шаблон реактора .

from twisted.internet import task, reactor

timeout = 60.0 # Sixty seconds

def doWork():
    #do work here
    pass

l = task.LoopingCall(doWork)
l.start(timeout) # call every sixty seconds

reactor.run()

Хоча "в той час як True: сон (60)", ймовірно, спрацює. Twisted, мабуть, вже реалізує багато функцій, які вам з часом знадобляться (демонізація, ведення журналів чи обробка винятків, як вказував bobince) і, ймовірно, буде більш надійним рішенням


Чудова відповідь також дуже точна без дрейфу. Цікаво, чи це ставить процесор спати також під час очікування виконання завдання (він же не зайнятий-чекає)?
smoothware

1
це дрейфує на рівні мілісекунд
Дерек Едем,

Що означає "дрейф на рівні мілісекунди"?
Жан-Поль Кальдероне

67

Якщо ви хочете періодично виконувати свою функцію, замість блокування нескінченного циклу я б використовував різьбовий таймер. Таким чином ваш код може продовжувати працювати і виконувати інші завдання, і все ще виконувати вашу функцію називається кожні n секунд Я дуже часто використовую цю техніку для друку інформації про прогрес у довгих завданнях процесора / диска / мережі.

Ось код, який я опублікував у подібному питанні, з контролем start () та stop ():

from threading import Timer

class RepeatedTimer(object):
    def __init__(self, interval, function, *args, **kwargs):
        self._timer     = None
        self.interval   = interval
        self.function   = function
        self.args       = args
        self.kwargs     = kwargs
        self.is_running = False
        self.start()

    def _run(self):
        self.is_running = False
        self.start()
        self.function(*self.args, **self.kwargs)

    def start(self):
        if not self.is_running:
            self._timer = Timer(self.interval, self._run)
            self._timer.start()
            self.is_running = True

    def stop(self):
        self._timer.cancel()
        self.is_running = False

Використання:

from time import sleep

def hello(name):
    print "Hello %s!" % name

print "starting..."
rt = RepeatedTimer(1, hello, "World") # it auto-starts, no need of rt.start()
try:
    sleep(5) # your long-running job goes here...
finally:
    rt.stop() # better in a try/finally block to make sure the program ends!

Особливості:

  • Лише стандартна бібліотека, ніяких зовнішніх залежностей
  • start()і stop()безпечно дзвонити кілька разів, навіть якщо таймер уже запущений / зупинений
  • Функція, яку потрібно викликати, може мати позиційні та іменні аргументи
  • Ви можете змінити його intervalбудь-коли, це буде ефективно після наступного запуску. Те саме args, kwargsі навіть function!

Це рішення, здається, пливе з часом; Мені потрібна була версія, яка має на меті викликати функцію кожні n секунд без дрейфу. Я опублікую оновлення в окремому запитанні.
eraoul

В def _run(self)Я намагаюся обернути навколо моєї голови , чому ви називаєте self.start()до того self.function(). Чи можете ви докладно? Я б подумав, що дзвонити start()спочатку self.is_runningзавжди буде Falseтак, тоді ми завжди закручуємо нову нитку.
Багатий Епіскопо

1
Я думаю, що я дістався до цього. @ Рішення MestreLion виконує функцію кожні xсекунди (тобто t = 0, t = 1x, t = 2x, t = 3x, ...), де на оригінальних плакатах зразок коду виконує функцію з інтервалом x секунди між ними. Крім того, це рішення, на мою думку, має помилку, якщо intervalвоно коротше часу, необхідного functionдля його виконання. У цьому випадку self._timerбуде перезаписано startфункцію.
Багатий Епіскопо

Так, @RichieEpiscopo, виклик .function()після .start()це запустити функцію при Т = 0. І я не думаю, що це буде проблемою, якщо це functionзайме більше часу interval, але так, у коді можуть бути деякі умови гонок.
MestreLion

Це єдиний неблокуючий спосіб, який я міг отримати. Дякую.
зворотний

35

Найпростіший спосіб я вважаю:

import time

def executeSomething():
    #code here
    time.sleep(60)

while True:
    executeSomething()

Таким чином ваш код виконується, потім він чекає 60 секунд, потім він знову виконується, чекає, виконує і т.д. ... Не потрібно ускладнювати речі: D


Ключове слово True має бути великим літером
Sean Cain

38
Насправді це не відповідь: час сну () може використовуватися лише для очікування X секунд після кожного виконання. Наприклад, якщо для виконання вашої функції потрібно 0,5 секунди, а ви використовуєте time.sleep (1), це означає, що ваша функція виконує кожні 1,5 секунди, а не 1. Ви повинні використовувати інші модулі та / або потоки, щоб переконатися, що щось працює протягом Y разів в кожну X секунду
kommradHomer

1
@kommradHomer: Відповідь Дейва Роува демонструє, що ви можете використовувати time.sleep()запускати щось кожні X секунд
jfs

2
На мій погляд , код повинен викликати time.sleep()в while Trueциклі , як:def executeSomething(): print('10 sec left') ; while True: executeSomething(); time.sleep(10)
Леонард Lepadatu

22
import time, traceback

def every(delay, task):
  next_time = time.time() + delay
  while True:
    time.sleep(max(0, next_time - time.time()))
    try:
      task()
    except Exception:
      traceback.print_exc()
      # in production code you might want to have this instead of course:
      # logger.exception("Problem while executing repetitive task.")
    # skip tasks if we are behind schedule:
    next_time += (time.time() - next_time) // delay * delay + delay

def foo():
  print("foo", time.time())

every(5, foo)

Якщо ви хочете зробити це, не блокуючи залишився код, ви можете скористатися цим, щоб він міг працювати у власній темі:

import threading
threading.Thread(target=lambda: every(5, foo)).start()

Це рішення поєднує кілька особливостей, які рідко зустрічаються в інших рішеннях:

  • Поводження з винятками : Наскільки це можливо на цьому рівні, винятки обробляються належним чином, тобто отримують реєстрацію для цілей налагодження без припинення нашої програми.
  • Ніякого ланцюжка: загальна ланцюгова реалізація (для планування наступної події), яку ви знайдете у багатьох відповідях, крихка в тому аспекті, що якщо щось піде не так у межах механізму планування ( threading.Timerабо будь-якого іншого), це припинить ланцюг. Подальші страти не відбудуться, навіть якщо причина проблеми вже виправлена. Простий цикл і очікування з простим sleep()набагато надійнішим порівняно.
  • Без дрейфу: моє рішення відстежує точний час, у який він повинен працювати. Немає дрейфу залежно від часу виконання (як у багатьох інших рішень).
  • Пропуск: Моє рішення пропустить завдання, якщо одне виконання зайняло занадто багато часу (наприклад, робити X кожні п’ять секунд, але на X потрібно 6 секунд). Це стандартна поведінка з крон (і з поважної причини). Багато інших рішень потім просто виконують завдання кілька разів поспіль без жодної затримки. У більшості випадків (наприклад, завдання з очищення) цього не хочеться. Якщо це буде завгодно, просто використовувати next_time += delayзамість цього.

2
найкраща відповідь за те, що не дрейфує.
Себастьян Старк

1
@PirateApp Я б робив це в іншій темі. Ви можете зробити це в тій самій нитці, але тоді ви закінчите програмувати власну систему планування, яка є занадто складною для коментаря.
Альфа

1
У Python, завдяки GIL, доступ до змінних у двох потоках є абсолютно безпечним. І просто читання в двох потоках ніколи не повинно бути проблемою (також не в інших потокових середовищах). Лише запис із двох різних потоків у системі без GIL (наприклад, у Java, C ++ тощо) потребує явної синхронізації.
Альфа

1
@ user50473 Без додаткової інформації я б спершу підійшов до завдання з потокової сторони. Один потік читає дані раз у раз, а потім спить, поки не настане час знову це зробити. Розчин вище можна використати для цього, звичайно. Але я міг уявити купу причин піти іншим шляхом. Так що удачі :)
Альфа

1
Сон можна замінити нарізанням різьбою. Зачекайте з таймаутом, щоб бути більш чутливим до виходу програми stackoverflow.com/questions/29082268 / ...
themadmax

20

Ось оновлення коду від MestreLion, що дозволяє уникнути дрейфування з часом.

Клас RepeatedTimer тут викликає задану функцію кожні "інтервали" секунд, як вимагає ОП; графік не залежить від того, скільки часу функція потребує виконання. Мені подобається це рішення, оскільки воно не має зовнішніх залежностей від бібліотеки; це просто чистий пітон.

import threading 
import time

class RepeatedTimer(object):
  def __init__(self, interval, function, *args, **kwargs):
    self._timer = None
    self.interval = interval
    self.function = function
    self.args = args
    self.kwargs = kwargs
    self.is_running = False
    self.next_call = time.time()
    self.start()

  def _run(self):
    self.is_running = False
    self.start()
    self.function(*self.args, **self.kwargs)

  def start(self):
    if not self.is_running:
      self.next_call += self.interval
      self._timer = threading.Timer(self.next_call - time.time(), self._run)
      self._timer.start()
      self.is_running = True

  def stop(self):
    self._timer.cancel()
    self.is_running = False

Використання зразка (скопійовано з відповіді MestreLion):

from time import sleep

def hello(name):
    print "Hello %s!" % name

print "starting..."
rt = RepeatedTimer(1, hello, "World") # it auto-starts, no need of rt.start()
try:
    sleep(5) # your long-running job goes here...
finally:
    rt.stop() # better in a try/finally block to make sure the program ends!

5

Я зіткнувся з подібною проблемою деякий час назад. Можливо, http://cronus.readthedocs.org може допомогти?

Для версії v0.2 працює наступний фрагмент

import cronus.beat as beat

beat.set_rate(2) # 2 Hz
while beat.true():
    # do some time consuming work here
    beat.sleep() # total loop duration would be 0.5 sec

4

Основна відмінність між цим і кроном полягає в тому, що виняток вб'є демона назавжди. Можливо, ви захочете скористатись виловлювачем та реєстратором винятків.


4

Одна можлива відповідь:

import time
t=time.time()

while True:
    if time.time()-t>10:
        #run your task here
        t=time.time()

1
Це зайнято в очікуванні, тому дуже погано.
Альфе

Гарне рішення для тих, хто шукає таймер, що не блокує.
Ноель

3

Я закінчив користуватися модулем розкладу . API приємний.

import schedule
import time

def job():
    print("I'm working...")

schedule.every(10).minutes.do(job)
schedule.every().hour.do(job)
schedule.every().day.at("10:30").do(job)
schedule.every(5).to(10).minutes.do(job)
schedule.every().monday.do(job)
schedule.every().wednesday.at("13:15").do(job)
schedule.every().minute.at(":17").do(job)

while True:
    schedule.run_pending()
    time.sleep(1)

Мені важко намагатися використовувати цей модуль, зокрема, мені потрібно розблокувати основний потік, я перевірив поширені запитання на веб-сайті документації розкладу, але я не дуже зрозумів надане вирішення. Хтось знає, де я можу знайти робочий приклад, який не блокує основну нитку?
5Daydreams

1

Я використовую метод Tkinter after (), який не «вкрадає гру» (як модуль планування, який був представлений раніше), тобто дозволяє іншим речам працювати паралельно:

import Tkinter

def do_something1():
  global n1
  n1 += 1
  if n1 == 6: # (Optional condition)
    print "* do_something1() is done *"; return
  # Do your stuff here
  # ...
  print "do_something1() "+str(n1)
  tk.after(1000, do_something1)

def do_something2(): 
  global n2
  n2 += 1
  if n2 == 6: # (Optional condition)
    print "* do_something2() is done *"; return
  # Do your stuff here
  # ...
  print "do_something2() "+str(n2)
  tk.after(500, do_something2)

tk = Tkinter.Tk(); 
n1 = 0; n2 = 0
do_something1()
do_something2()
tk.mainloop()

do_something1()і do_something2()може працювати паралельно та з будь-якою інтервальною швидкістю. Тут другий буде виконуватися вдвічі швидше. Зауважте також, що я використовував простий лічильник як умову для припинення будь-якої функції. Ви можете використовувати будь-яку іншу конфігурацію, яка вам подобається, або жодну, якщо функцію запускати до завершення програми (наприклад, годинник).


Будьте обережні зі своїм формулюванням: afterне дозволяє паралельно працювати. Tkinter є однопоточним і може робити лише одне. Якщо щось заплановане afterзапускається, воно не працює паралельно з рештою коду. Якщо обидва do_something1і do_something2планується запустити одночасно, вони працюватимуть послідовно, а не паралельно.
Брайан Оуклі

@Apostolos все ваше рішення робить використовувати Tkinter MainLoop замість SCHED основного циклу, тому він працює точно таким же чином , але дозволяє TkInter інтерфейси продовжувати відповідати на запити. Якщо ви не використовуєте tkinter для інших речей, то це нічого не змінить щодо планового рішення. Ви можете використовувати дві або більше запланованих функцій з різними інтервалами в schedрішенні, і вона буде працювати точно так само, як і ваша.
nosklo

Ні, це працює не так. Я це пояснив. Той, хто "блокує" програму (тобто зупиняє потік, ви нічого не можете робити - навіть не запускаючи іншу планову роботу, як ви пропонуєте), поки вона не закінчиться, а інша не дозволить ваші руки / вільні (тобто ви можете робити інші речі після того, як він почався. Вам не доведеться чекати, поки він закінчиться. Це величезна різниця. Якби ви спробували метод, який я представив, ви б побачили самі. Я спробував ваш. спробуй і мій?
Апостолос

1

Ось адаптована версія до коду від MestreLion. Окрім оригінальної функції, цей код:

1) додати first_interval, який використовується для запуску таймера в певний час (абонент повинен обчислити first_interval і ввести)

2) вирішити умову перегонів у вихідному коді. У початковому коді, якщо керуюча нитка не змогла скасувати запущений таймер ("Зупиніть таймер та скасуйте виконання дії таймера. Це буде працювати лише в тому випадку, якщо таймер все ще знаходиться на етапі очікування". Цитується з https: // docs.python.org/2/library/threading.html ) таймер працюватиме нескінченно.

class RepeatedTimer(object):
def __init__(self, first_interval, interval, func, *args, **kwargs):
    self.timer      = None
    self.first_interval = first_interval
    self.interval   = interval
    self.func   = func
    self.args       = args
    self.kwargs     = kwargs
    self.running = False
    self.is_started = False

def first_start(self):
    try:
        # no race-condition here because only control thread will call this method
        # if already started will not start again
        if not self.is_started:
            self.is_started = True
            self.timer = Timer(self.first_interval, self.run)
            self.running = True
            self.timer.start()
    except Exception as e:
        log_print(syslog.LOG_ERR, "timer first_start failed %s %s"%(e.message, traceback.format_exc()))
        raise

def run(self):
    # if not stopped start again
    if self.running:
        self.timer = Timer(self.interval, self.run)
        self.timer.start()
    self.func(*self.args, **self.kwargs)

def stop(self):
    # cancel current timer in case failed it's still OK
    # if already stopped doesn't matter to stop again
    if self.timer:
        self.timer.cancel()
    self.running = False

1

Це здається набагато простішим, ніж прийняте рішення - чи є у нього недоліки, які я не розглядаю? Приїхав сюди, шукаючи якусь мертву-просту копію макаронних виробів і розчарувався.

import threading, time

def print_every_n_seconds(n=2):
    while True:
        print(time.ctime())
        time.sleep(n)

thread = threading.Thread(target=print_every_n_seconds, daemon=True)
thread.start()

Який асинхронно виводить.

#Tue Oct 16 17:29:40 2018
#Tue Oct 16 17:29:42 2018
#Tue Oct 16 17:29:44 2018

Це має відхилення в тому сенсі, що якщо виконання завдання займає значну кількість часу, то інтервал стає 2 секунди + час виконання завдання, тож якщо вам потрібно точне планування, це не для вас.

Зауважте, що daemon=Trueпрапор означає, що цей потік не блокує програму відключення. Наприклад, було pytestвипущено питання про те, де б висіти нескінченно після запуску тестів, очікуючи припинення цієї теди.


Ні, він друкує лише першу дату, а потім зупиняється ...
Алекс Пока

Ви впевнені - я просто копіюю і вставляю в термінал. Він повертається одразу, але роздруківка продовжується у фоновому режимі для мене.
Адам Хьюз

Схоже, я щось тут пропускаю. Я копіювати / вставити код в test.py , і працювати з пітона test.py . За допомогою Python2.7 мені потрібно видалити daemon = True, що не розпізнається, і я прочитав кілька відбитків. З Python3.8 він припиняється після першої друку, і жоден процес не закінчується після його закінчення. Видалення демона = Правда, я прочитав кілька відбитків ...
Алекс Пока

хм дивно - я на python 3.6.10, але не знаю, чому це має значення
Адам Хьюз

Знову ж таки: Python3.4.2 (Debian GNU / Linux 8 (jessie)), довелося видалити daemon = True, щоб він міг друкувати багаторазово. З демоном я отримую синтаксичну помилку. Попередні тести з Python2.7 та 3.8 були на Ubuntu 19.10 Чи може бути, що до демона по-різному ставляться відповідно до ОС?
Алекс Пока

0

Я використовую це, щоб викликати 60 подій на годину, при цьому більшість подій відбувалися за ту ж кількість секунд після всієї хвилини:

import math
import time
import random

TICK = 60 # one minute tick size
TICK_TIMING = 59 # execute on 59th second of the tick
TICK_MINIMUM = 30 # minimum catch up tick size when lagging

def set_timing():

    now = time.time()
    elapsed = now - info['begin']
    minutes = math.floor(elapsed/TICK)
    tick_elapsed = now - info['completion_time']
    if (info['tick']+1) > minutes:
        wait = max(0,(TICK_TIMING-(time.time() % TICK)))
        print ('standard wait: %.2f' % wait)
        time.sleep(wait)
    elif tick_elapsed < TICK_MINIMUM:
        wait = TICK_MINIMUM-tick_elapsed
        print ('minimum wait: %.2f' % wait)
        time.sleep(wait)
    else:
        print ('skip set_timing(); no wait')
    drift = ((time.time() - info['begin']) - info['tick']*TICK -
        TICK_TIMING + info['begin']%TICK)
    print ('drift: %.6f' % drift)

info['tick'] = 0
info['begin'] = time.time()
info['completion_time'] = info['begin'] - TICK

while 1:

    set_timing()

    print('hello world')

    #random real world event
    time.sleep(random.random()*TICK_MINIMUM)

    info['tick'] += 1
    info['completion_time'] = time.time()

Залежно від реальних умов у вас можуть з’явитися кліщі довжини:

60,60,62,58,60,60,120,30,30,60,60,60,60,60...etc.

але наприкінці 60 хвилин у вас буде 60 кліщів; і більшість з них відбуватиметься при правильному зміщенні до тієї хвилини, яку ви віддаєте перевагу.

У моїй системі я отримую типовий дрейф <1/20 секунди, поки не з’явиться потреба в корекції.

Перевагою цього способу є дозвіл дрейфу годинника; що може спричинити проблеми, якщо ви робите такі речі, як додавання одного елемента за галочку, і ви очікуєте 60 доданих елементів на годину. Незрахунок дрейфу може спричинити, що вторинні ознаки, такі як ковзаючі середні, вважають дані занадто глибокими в минуле, що призводить до несправного виведення.


0

наприклад, Показувати поточний місцевий час

import datetime
import glib
import logger

def get_local_time():
    current_time = datetime.datetime.now().strftime("%H:%M")
    logger.info("get_local_time(): %s",current_time)
    return str(current_time)

def display_local_time():
    logger.info("Current time is: %s", get_local_time())
    return True

# call every minute
glib.timeout_add(60*1000, display_local_time)

0
    ''' tracking number of times it prints'''
import threading

global timeInterval
count=0
def printit():
  threading.Timer(timeInterval, printit).start()
  print( "Hello, World!")
  global count
  count=count+1
  print(count)
printit

if __name__ == "__main__":
    timeInterval= int(input('Enter Time in Seconds:'))
    printit()

На основі введення користувача він буде повторювати цей метод на кожному інтервалі часу.
raviGupta

0

Ось ще одне рішення без використання зайвих бібліотек.

def delay_until(condition_fn, interval_in_sec, timeout_in_sec):
    """Delay using a boolean callable function.

    `condition_fn` is invoked every `interval_in_sec` until `timeout_in_sec`.
    It can break early if condition is met.

    Args:
        condition_fn     - a callable boolean function
        interval_in_sec  - wait time between calling `condition_fn`
        timeout_in_sec   - maximum time to run

    Returns: None
    """
    start = last_call = time.time()
    while time.time() - start < timeout_in_sec:
        if (time.time() - last_call) > interval_in_sec:
            if condition_fn() is True:
                break
            last_call = time.time()
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.