É sleep () uma boa idéia para o loop principal de um aplicativo de agendamento de tarefas

StackOverflow https://stackoverflow.com/questions/1179301

Pergunta

Eu estou escrevendo um aplicativo de agendamento de tarefas em Ruby para o meu trabalho (principalmente para mover arquivos usando vários protocolos em uma determinada frequência)

As minhas principais olhares loop como este:

while true do
  # some code to launch the proper job
  sleep CONFIG["interval"]
end

Ele está trabalhando como um encanto, mas eu não tenho certeza se é seguro o suficiente como o aplicativo pode ser executado em um servidor com software em execução da CPU.

Existe outra maneira de fazer a mesma coisa, ou é sleep() seguro o suficiente no meu caso?

Foi útil?

Solução

Usando o sono é provavelmente OK para coisas rápidas e sujas. Mas para as coisas que precisam de um pouco mais robustez ou confiabilidade sugiro que o sono é mal :) O problema com o sono é que o segmento é (estou assumindo o Windows aqui ...) é realmente dormindo - o programador não será executado o fio até algum tempo depois de intervalo de suspensão tenha passado.

Durante este tempo, o fio não vai acordar para qualquer coisa. Isso significa que ele não pode ser cancelado, ou acordar para processar algum tipo de evento. Naturalmente, o processo pode ser morto, mas que não dá o fio dormir uma oportunidade de acordar e limpa qualquer coisa.

Eu não estou familiarizado com Ruby, mas presumo que tem algum tipo de facilidade para esperando em várias coisas. Se você puder, eu sugiro que em vez de usar sono, você waint em duas coisas \

  1. Um timer que acorda o segmento periodicamente para fazer o seu trabalho.
  2. Um evento que é definido quando ele processar as necessidades de cancelar ou bastante (prendendo control-C, por exemplo).

Seria ainda melhor se houver algum tipo de evento que pode ser usado para sinalizar a necessidade de fazer o trabalho. Isso evitaria polling em um temporizador. Isso geralmente leva a uma menor utilização de recursos e um sistema mais ágil.

Outras dicas

Toda vez que eu sinto a necessidade de bloquear, eu uso um loop de evento; geralmente libev. Aqui é um rubi de ligação:

http://rev.rubyforge.org/rdoc/

Basicamente, sleep é perfeitamente bem se você quiser que o seu processo de ir dormir sem ter qualquer outra coisa acontecendo em segundo plano. Se você quiser fazer outras coisas, embora, como o sono e também esperar por conexões TCP ou um filehandle para se tornar legível, então você vai ter que usar um loop de evento. Então, por que não usar um no início?

O fluxo de sua aplicação será:

main {
   Timer->new( after => 0, every => 60 seconds, run => { <do your work> } )
   loop();
}

Quando você quer fazer outras coisas, que você acabou de criar o observador, e isso acontece para você. (Os postos de trabalho que você está executando também pode criar observadores.)

Se você não precisa de um intervalo exato, então faz sentido para mim. Se você precisa de ser acordado em horários regulares sem resvalar, você provavelmente vai querer usar algum tipo de temporizador externo. Mas quando você está dormindo, você não está usando recursos da CPU. É o interruptor de tarefa que é caro.

Enquanto sleep(timeout) é perfeitamente apropriada para alguns projetos, há uma ressalva importante ter em mente.

Rubi instala manipuladores de sinais com SA_RESTART (ver aqui ), o que significa que o seu sleep (ou select(nil, nil, nil, timeout) equivalente) não podem ser facilmente interrompido. Seu manipulador de sinal vai disparar, mas o programa vai voltar direito de sleep. Isso pode ser inconveniente se você queria reagir oportuna para, digamos, um SIGTERM.

Considere que ...

#! /usr/bin/ruby
Signal.trap("USR1") { puts "Hey, wake up!" }
Process.fork() { sleep 2 and Process.kill("USR1", Process.ppid) }
sleep 30
puts "Zzz.  I enjoyed my nap."

... levará cerca de 30 segundos para executar, em vez de 2.

Como alternativa, você pode em vez lançar uma exceção no seu manipulador de sinal, que iria interromper o sono (ou qualquer outra coisa!) Acima. Você também pode mudar para um loop-base select e usar uma variante do href="http://cr.yp.to/docs/selfpipe.html" rel="nofollow noreferrer"> truque auto-pipe acordar "cedo" após a recepção de um sinal. Como outros apontaram, bibliotecas evento cheio de recursos estão disponíveis, também.

Não vai usar CPU enquanto ele está dormindo, mas se você está dormindo por um longo tempo eu estaria mais preocupado do rubi correndo intérprete segurando memória enquanto ele não estava fazendo nada. Esta não é tão grande de um negócio tho.

scroll top