2010-02-08 2 views
50

Я хочу выполнять функцию каждые 60 секунд на Python, но я не хочу, чтобы меня блокировали между тем.Как выполнять функцию асинхронно каждые 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 секунд времени. В конце он дает ошибку, и я думаю, что это потому, что threading.timer не был отменен.

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

Заранее благодарен!

+0

Ваша программа заканчивается после нереста первого таймера. –

+0

Чтобы отменить Таймер, вам нужно где-то ссылаться на него и вызвать его метод 'cancel'. –

+0

Обратите внимание, что все решения, опубликованные до сих пор, страдают от (небольшого) кумулятивного нарастания ошибки. То есть вместо вычисления следующей продолжительности сна, основанной на фиксированном времени начала, они просто спят за «еще 60 секунд». Это никогда не будет спать меньше 60 лет и обычно будет спать чуть больше 60 секунд. Это не всегда проблема, но если вы хотите спать ровно 1440 раз в день, убедитесь, что вы компенсируете эту ошибку. –

ответ

87

Вы могли бы попробовать класс 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() 
+0

с тем кодом, который он выполняет только один раз, есть что-то не хватает для выполнения большего количества раз? –

+3

Вам нужно '.start()' Timer, я его отредактировал. –

+0

К сожалению, спасибо за добавление .start() ... Я должен был скопировать/вставить из моего интерпретатора :). Теперь он действительно должен вызываться каждые 60 секунд, а не только один раз. –

0

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

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

Это не Python. –

+1

Нет, но это идея. Когда я ответил, кода не было, так что это была просто идея. – Aif

+0

@MikeGraham Не могли бы вы объяснить, почему это не Python? – Dunatotatos

2

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

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


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

timer = BackgroundTimer() 
timer.start() 

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

+0

Надеюсь, вы понимаете, что пустой метод '__init__' является излишним :) –

+0

Конечно ... исправлено :-) Спасибо. – 0xfe

+0

Способ быть независимым от времени выполнения - использовать часы реального времени (например, 'time.time()' или 'datetime.now() '), проверьте время в начале выполнения задачи, добавьте 60 секунд, чтобы получить время для следующего обжига, а затем еще раз проверьте в конце и вычтите это из следующего времени стрельбы, чтобы получить время сна. –

2

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

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

+0

Ловушка с этим таймером GUI заключается в том, что графический интерфейс заморожен во время обработки таймаута. Если задача короткая, проблем нет. Если нет, то ваша программа, кажется, виснет каждую минуту. –

2

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

.callEvent(self, event, *channels) метод цепей содержит огонь и приостановить, пока-ответ функциональность, документация говорит:

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

Я надеюсь, что вы нашли это так полезно, как я :)
./regards

+0

Хотя немного от темы. Это отличная ссылка. – Glycerine

1

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

import time 

def wait(n): 
    '''Wait until the next increment of n seconds''' 
    x = time.time() 
    time.sleep(n-(x%n)) 
    print time.asctime() 
1

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

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 секунд time.sleep (10). В конце бежит поток отменяется.

Смежные вопросы