Как выполнять функцию асинхронно каждые 60 секунд в Python? - PullRequest
54 голосов
/ 08 февраля 2010

Я хочу выполнять функцию каждые 60 секунд на Python, но пока не хочу, чтобы меня блокировали.

Как я могу сделать это асинхронно?

import threading
import time

def f():
    print("hello world")
    threading.Timer(3, f).start()

if __name__ == '__main__':
    f()    
    time.sleep(20)

С этим кодом функция f выполняется каждые 3 секунды в течение 20 секунд time.time. В конце это выдает ошибку, и я думаю, что это потому, что threading.timer не был отменен.

Как я могу отменить это?

Заранее спасибо!

Ответы [ 7 ]

96 голосов
/ 08 февраля 2010

Вы можете попробовать Threading.Timer класс: http://docs.python.org/library/threading.html#timer-objects.

import threading

def f(f_stop):
    # do something here ...
    if not f_stop.is_set():
        # call f() again in 60 seconds
        threading.Timer(60, f, [f_stop]).start()

f_stop = threading.Event()
# start calling f now and every 60 sec thereafter
f(f_stop)

# stop the thread when needed
#f_stop.set()
2 голосов
/ 05 августа 2013

Я погуглил и нашел схемы Python Framework, которые позволяют ждать
для конкретного события.

Метод схем .callEvent(self, event, *channels) содержит функции запуска и приостановки до ответа, в документации сказано:

Запустить указанное событие для указанных каналов и приостановить выполнение. пока он не был отправлен. Этот метод может быть вызван только как аргумент yield на верхнем уровне выполнения обработчика (например, "yield self.callEvent(event)"). Эффективно создает и возвращает генератор, который будет вызываться главным циклом, пока событие не отправлен (см .: func: circuits.core.handlers.handler).

Надеюсь, вы найдете его таким же полезным, как и я :)
./regards

2 голосов
/ 08 февраля 2010

Это зависит от того, что вы на самом деле хотите делать в это время.Потоки - самый общий и наименее предпочтительный способ сделать это;при его использовании вы должны знать о проблемах с многопоточностью: не весь (не Python) код допускает доступ из нескольких потоков одновременно, связь между потоками должна осуществляться с использованием потоковобезопасных структур данных, таких как Queue.Queue, вы не будетевозможность прерывать поток извне, а завершение программы во время работы потока может привести к зависанию интерпретатора или ложным следам возврата.

Часто существует более простой способ.Если вы делаете это в программе с графическим интерфейсом, используйте функцию таймера или события библиотеки графического интерфейса.Все GUI имеют это.Аналогично, если вы используете другую систему событий, например Twisted или другую модель серверного процесса, вы должны иметь возможность подключиться к основному циклу событий, чтобы он регулярно вызывал вашу функцию.Подходы без многопоточности приводят к блокировке вашей программы во время ожидания функции, но не между вызовами функций.

2 голосов
/ 08 февраля 2010

Самый простой способ - создать фоновый поток, который запускается каждые 60 секунд. Тривиальная реализация:

class BackgroundTimer(Thread):   
   def run(self):
      while 1:
        Time.sleep(60)
        # do something


# ... SNIP ...
# Inside your main thread
# ... SNIP ...

timer = BackgroundTimer()
timer.start()

Очевидно, что если «сделать что-то» занимает много времени, вам нужно учесть это в своем заявлении о сне. Но это служит хорошим приближением.

1 голос
/ 06 октября 2017

Я думаю, что правильный способ повторного запуска потока следующий:

import threading
import time

def f():
    print("hello world")  # your code here
    myThread.run()

if __name__ == '__main__':
    myThread = threading.Timer(3, f)  # timer is set to 3 seconds
    myThread.start()
    time.sleep(10)  # it can be loop or other time consuming code here
    if myThread.is_alive():
        myThread.cancel()

С этим кодом функция f выполняется каждые 3 секунды в течение 10 секунд. Сон (10). В конце запуск потока отменяется.

1 голос
/ 02 июля 2015

Если вы хотите вызвать метод «на часах» (например, каждый час на час ), вы можете интегрировать следующую идею с любым выбранным вами механизмом потоков:

import time

def wait(n):
    '''Wait until the next increment of n seconds'''
    x = time.time()
    time.sleep(n-(x%n))
    print time.asctime()
0 голосов
/ 08 февраля 2010

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

#!/usr/bin/env python
import time
while True:
   # Your code here
   time.sleep(60)
...