Quero executar repetidamente uma função em Python a cada 60 segundos para sempre (assim como um NSTimer no Objective C). Esse código será executado como um daemon e é efetivamente como chamar o script python a cada minuto usando um cron, mas sem exigir que isso seja configurado pelo usuário.
Em esta pergunta sobre um cron implementado em Python , a solução parece efetivamente apenas sleep () para x segundos. Eu não preciso de funcionalidades tão avançadas, então talvez algo assim funcione
while True:
# Code executed here
time.sleep(60)
Existem problemas previsíveis com este código?
time.sleep(60)
pode retornar tanto mais cedo e mais tardeRespostas:
Se o seu programa não tem um ciclo de eventos já, use o sched módulo, que implementa um evento planejador de propósito geral.
Se você já estiver usando uma biblioteca de ciclo de eventos como
asyncio
,trio
,tkinter
,PyQt5
,gobject
,kivy
, e muitos outros - basta agendar a tarefa usando métodos da sua biblioteca ciclo de eventos existente, em vez disso.fonte
enterabs()
para evitá-lo. Aqui está uma versão não-drifting para comparação .time.sleep
podem acumular-se aqui. "executar a cada X segundos" e "executar com um atraso de ~ X segundos repetidamente" não são os mesmos. Veja também este comentárioBasta travar seu loop de tempo no relógio do sistema. Fácil.
fonte
twisted
resposta são as únicas respostas que executam uma função a cadax
segundo. O restante executa a função com um atraso dex
segundos após cada chamada.from time import time, sleep
por causa das implicações existenciais;)starttime
se você começar a sincronizá-lo em um determinado período:time.sleep(60 - time.time() % 60)
está funcionando bem para mim. Eu o usei comotime.sleep(1200 - time.time() % 1200)
e ele me fornece os logs:00 :20 :40
exatamente como eu queria.sleep()
,timer()
precisão e quanto tempo leva para executar o corpo do loop, mas em iterações média ocorrem sempre nos limites do intervalo (mesmo que alguns são ignorados):while keep_doing_it(): sleep(interval - timer() % interval)
. Compare-o apenas com o localwhile keep_doing_it(): sleep(interval)
onde os erros podem se acumular após várias iterações.Você pode considerar o Twisted, que é uma biblioteca de rede Python que implementa o Padrão do Reator .
Embora "while True: sleep (60)" provavelmente funcione, o Twisted provavelmente já implementa muitos dos recursos que você eventualmente precisará (daemonization, log ou manipulação de exceções, conforme indicado por bobince) e provavelmente será uma solução mais robusta.
fonte
Se você quiser uma maneira sem bloqueio de executar sua função periodicamente, em vez de um loop infinito de bloqueio, eu usaria um temporizador de threads. Dessa forma, seu código pode continuar em execução e executar outras tarefas e ainda ter sua função chamada a cada n segundos. Eu uso muito essa técnica para imprimir informações de progresso em tarefas longas, com uso intenso de CPU / Disco / Rede.
Aqui está o código que eu postei em uma pergunta semelhante, com o controle start () e stop ():
Uso:
Recursos:
start()
estop()
é seguro ligar várias vezes, mesmo que o timer já tenha iniciado / paradointerval
qualquer momento, entrará em vigor após a próxima execução. Mesmo paraargs
,kwargs
e até mesmofunction
!fonte
def _run(self)
Eu estou tentando envolver minha cabeça em torno de por que você chamarself.start()
antesself.function()
. Você pode elaborar? Eu acho que chamandostart()
primeiroself.is_running
seria sempreFalse
assim, então sempre criaríamos um novo tópico.x
segundo (ou seja, t = 0, t = 1x, t = 2x, t = 3x, ...) onde no código de exemplo dos pôsteres originais executa uma função com um intervalo de x segundos. Além disso, acredito que esta solução tenha um erro seinterval
for menor que o tempo necessáriofunction
para executar. Nesse caso,self._timer
será substituído nastart
função..function()
after.start()
é executar a função em t = 0. E eu não acho que será um problema sefunction
demorar mais do que issointerval
, mas sim, pode haver algumas condições de corrida no código.A maneira mais fácil que acredito ser:
Dessa forma, seu código é executado, então ele aguarda 60 segundos e depois é executado novamente, espera, executa, etc ... Não há necessidade de complicar as coisas: D
fonte
time.sleep()
algo em execução a cada X segundostime.sleep()
emwhile True
loop como:def executeSomething(): print('10 sec left') ; while True: executeSomething(); time.sleep(10)
Se você quiser fazer isso sem bloquear o código restante, use-o para permitir que ele seja executado em seu próprio encadeamento:
Esta solução combina vários recursos raramente encontrados combinados nas outras soluções:
threading.Timer
ou o que seja), isso encerrará a cadeia. Nenhuma execução adicional ocorrerá, mesmo que o motivo do problema já esteja corrigido. Um loop simples e esperar com um simplessleep()
é muito mais robusto em comparação.next_time += delay
em seu lugar.fonte
Aqui está uma atualização para o código do MestreLion que evita o desvio ao longo do tempo.
A classe RepeatedTimer aqui chama a função fornecida a cada "intervalo" de segundos, conforme solicitado pelo OP; o agendamento não depende de quanto tempo a função leva para executar. Eu gosto dessa solução, pois ela não possui dependências de bibliotecas externas; isso é apenas python puro.
Exemplo de uso (copiado da resposta do MestreLion):
fonte
Eu enfrentei um problema semelhante há algum tempo. Pode ser http://cronus.readthedocs.org possa ajudar?
Para a v0.2, o seguinte snippet funciona
fonte
A principal diferença entre isso e cron é que uma exceção mata o daemon para sempre. Você pode querer quebrar com um coletor e registrador de exceções.
fonte
Uma resposta possível:
fonte
Acabei usando o módulo de agendamento . A API é legal.
fonte
Eu uso o método Tkinter after (), que não "rouba o jogo" (como o módulo sched que foi apresentado anteriormente), ou seja, permite que outras coisas sejam executadas em paralelo:
do_something1()
edo_something2()
pode funcionar em paralelo e em qualquer velocidade de intervalo. Aqui, o segundo será executado duas vezes mais rápido. Observe também que usei um contador simples como condição para finalizar qualquer função. Você pode usar qualquer outra afirmação que desejar ou nenhuma, se quiser executar uma função até que o programa termine (por exemplo, um relógio).fonte
after
não permite que as coisas funcionem paralelamente. O Tkinter é de thread único e pode fazer apenas uma coisa de cada vez. Se algo agendadoafter
estiver em execução, ele não estará em paralelo com o restante do código. Se ambosdo_something1
edo_something2
estiverem programados para serem executados ao mesmo tempo, eles serão executados sequencialmente, não em paralelo.sched
solução e ela funcionará exatamente da mesma forma que a sua.Aqui está uma versão adaptada ao código do MestreLion. Além da função original, este código:
1) adicione first_interval usado para disparar o timer em um horário específico (o chamador precisa calcular o first_interval e passar)
2) resolva uma condição de corrida no código original. No código original, se o encadeamento de controle falhar ao cancelar o cronômetro em execução ("Interrompa o cronômetro e cancele a execução da ação do cronômetro. Isso funcionará apenas se o cronômetro ainda estiver no estágio de espera".) Citado em https: // docs.python.org/2/library/threading.html ), o cronômetro será executado indefinidamente.
fonte
Isso parece muito mais simples do que a solução aceita - há falhas que não estou considerando? Vim aqui à procura de algumas massas cópia simples e muito desapontado.
Que gera assincronamente.
Existe uma tendência no sentido de que, se a tarefa que está sendo executada leva uma quantidade considerável de tempo, o intervalo se torna 2 segundos + tempo da tarefa; portanto, se você precisar de agendamento preciso, isso não é para você.
Observe que o
daemon=True
sinalizador significa que esse encadeamento não impedirá o desligamento do aplicativo. Por exemplo, teve um problema em quepytest
seria interrompido indefinidamente após a execução de testes aguardando o término desse passo.fonte
Eu uso isso para causar 60 eventos por hora, com a maioria dos eventos ocorrendo no mesmo número de segundos após o minuto inteiro:
Dependendo das condições reais, você pode obter tiques de comprimento:
mas no final de 60 minutos você terá 60 ticks; e a maioria deles ocorrerá no deslocamento correto para o minuto que você preferir.
No meu sistema, recebo um desvio típico de <1/20 de segundo até que a necessidade de correção surja.
A vantagem deste método é a resolução do desvio do relógio; o que pode causar problemas se você anexar um item por tick e esperar 60 itens anexados por hora. A falta de consideração da deriva pode fazer com que indicações secundárias, como médias móveis, considerem os dados muito profundos no passado, resultando em saída defeituosa.
fonte
por exemplo, Exibir hora local atual
fonte
fonte
Aqui está outra solução sem o uso de bibliotecas extras.
fonte