Tamanho: 8536
Comentário: A palavra "fevereiro" é com letra minúscula, isso *não* é inglês Felipe!
|
Tamanho: 8539
Comentário:
|
Deleções são marcadas assim. | Adições são marcadas assim. |
Linha 4: | Linha 4: |
Em fevereiro de 2004 surgiu na lista python-brasil [http://br.groups.yahoo.com/group/python-brasil/message/213 uma pergunta] sobre como se pode executar uma determinada função de intervalos em intervalos, como a [http://www.devguru.com/Technologies/ecmascript/quickref/win_setInterval.html função setInterval] do {{{JavaScript}}}. Uma primeira solução utilizando apenas funções e timers foi proposta por [http://jonasgalvez.com/blog Jonas Galvez], uma segunda foi proposta por mim (FelipeLessa) e uma outra terceira foi achada também por Jonas. Cada solução tem suas vantagens e desvantagens, veja cada uma e tire sua própria conclusão quanto preferências de implementação e aplicabilidade no seu código. | Em fevereiro de 2004 surgiu na lista python-brasil [http://br.groups.yahoo.com/group/python-brasil/message/213 uma pergunta] sobre como se pode executar uma determinada função de intervalos em intervalos, como a [http://www.devguru.com/Technologies/ecmascript/quickref/win_setInterval.html função setInterval] do {{{JavaScript}}}. Uma primeira solução utilizando apenas funções e timers foi proposta por [http://jonasgalvez.com/br/blog Jonas Galvez], uma segunda foi proposta por mim (FelipeLessa) e uma outra terceira foi achada também por Jonas. Cada solução tem suas vantagens e desvantagens, veja cada uma e tire sua própria conclusão quanto preferências de implementação e aplicabilidade no seu código. |
Receita: Executando Funções em Intervalos de Tempo
Em fevereiro de 2004 surgiu na lista python-brasil [http://br.groups.yahoo.com/group/python-brasil/message/213 uma pergunta] sobre como se pode executar uma determinada função de intervalos em intervalos, como a [http://www.devguru.com/Technologies/ecmascript/quickref/win_setInterval.html função setInterval] do JavaScript. Uma primeira solução utilizando apenas funções e timers foi proposta por [http://jonasgalvez.com/br/blog Jonas Galvez], uma segunda foi proposta por mim (FelipeLessa) e uma outra terceira foi achada também por Jonas. Cada solução tem suas vantagens e desvantagens, veja cada uma e tire sua própria conclusão quanto preferências de implementação e aplicabilidade no seu código.
Primeira solução -- usando funções
Descrição
Essa é a primeira solução proposta. Basicamente uma função geradora cria uma outra que possui dentro de si um [http://www.python.org/doc/current/lib/timer-objects.html Timer()] que, ao invés de chamar a função que foi solicitada, chama a si própria, recriando o Timer() que foi destruído e executando a função. Uma outra função acessa um valor interno da função que está rodando o Timer() e a instrui para parar o loop.
Vantagens & Desvantagens
A vantagem clara é a simplicidade do código e de como ele é mantido, porém essa solução tem um ponto fraco: os ciclos de CPU e os recursos de sistema que são gastos com a criação e a destruição contínua dos objetos Timer(). É claro que essa diferença pode não ser percebida em intervalos grandes como o dos exemplos abaixo, porém em intervalos de décimos ou centésimos de segundo essa pode ser uma grande diferença.
Código
Exemplo de uso
1 # Nos exemplos assumirei que o módulo "cookbook" contém todos os códigos
2 from cookbook import setInterval
3 from os.path import getsize
4
5 FILE = '/var/log/syslog'
6
7 def monitor(lastsize = [-1])
8 size = getsize(FILE)
9 if size <> lastsize[0]:
10 print 'O tamanho do arquivo agora é %d kilobytes (%d bytes)' % \
11 (round(size / 1024.0), size)
12 lastsize[0] = size
13
14 if __name__ == '__main__':
15 print 'Checando a cada um minuto o tamanho do arquivo "%s".' % FILE
16 print 'Atenção: esse programa NUNCA termina.'
17 interval_monitor = setInterval(monitor, 60)
18 while 1:
19 pass
Segunda solução -- usando classes e sleep
Descrição
Essa é a segunda solução proposta por FelipeLessa também na [http://br.groups.yahoo.com/group/python-brasil/message/217 lista python-brasil]. Ao invés de um Timer() ser recriado constantemente, a função [http://www.python.org/doc/current/lib/module-time.html time.sleep()] é utilizada dentro de um laço while, dessa forma evitando a contrução/destruição de objetos constante.
Para os curiosos, as únicas diferenças entre o exemplo dessa solução e da primeira estão nas linhas 17, 18 e 19.
Vantagens & Desvantagens
Essa implementação praticamente não gasta qualquer tipo de recurso entre uma execução e outra, tendo entre elas apenas a função time.sleep() e a checagem do laço while, dessa forma tendo praticamente nenhuma sobrecarga mesmo em intervalos curtos.
A única desvantagem é visual: há quem não goste de utilizar classes para esse tipo de tarefa.
Código
1 from threading import Thread
2 from time import sleep
3
4 class IntervalRunner(Thread):
5 def __init__(self, interval, func, *args, **kwargs):
6 super(self, IntervalRunner).__init__(self)
7
8 self.interval = interval
9 self.func = func
10 self.args = args
11 self.kwargs = kwargs
12 self.executing = False
13
14 def run(self):
15 self.executing = True
16 self.func(*self.args, **self.kwargs)
17 while self.executing:
18 time.sleep(self.interval)
19 self.func(*self.args, **self.kwargs)
20
21 def stop(self):
22 self.executing = False
Exemplo de uso
1 # Nos exemplos assumirei que o módulo "cookbook" contém todos os códigos
2 from cookbook import IntervalRunner
3 from os.path import getsize
4
5 FILE = '/var/log/syslog'
6
7 def monitor(lastsize = [-1])
8 size = getsize(FILE)
9 if size <> lastsize[0]:
10 print 'O tamanho do arquivo agora é %d kilobytes (%d bytes)' % \
11 (round(size / 1024.0), size)
12 lastsize[0] = size
13
14 if __name__ == '__main__':
15 print 'Checando a cada um minuto o tamanho do arquivo "%s".' % FILE
16 print 'Atenção: esse programa NUNCA termina.'
17 interval_monitor = IntervalRunner(60, monitor)
18 interval_monitor.start()
19 interval_monitor.join()
Terceira solução -- usando classes e eventos
Descrição
Essa é a terceira solução proposta (e última, pelo menos enquanto eu escrevo ), originalmente postada no [http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/65222 ASPN Python Cookbook]. Para utilizá-la você precisa criar uma subclasse da mesma e o checador de atividade é implementado usando um objeto [http://www.python.org/doc/current/lib/event-objects.html Event()].
Vantagens & Desvantagens
Pode-se dizer que essa solução é uma irmã da segunda, filosofia igual e implementação diferente. Ao invés dela chamar uma função, ela já possui em si a função, o que significa que você deve criar uma subclasse. Essa é então a vantagem e a desvantagem. Se você precisa de um maior controle talvez goste dessa implementação, mas para tarefas simples é o mesmo que matar mosca com rifle de elefante.
Código
1 import threading
2
3 class TaskThread(threading.Thread):
4 """Thread that executes a task every N seconds"""
5
6 def __init__(self):
7 threading.Thread.__init__(self)
8 self._finished = threading.Event()
9 self._interval = 15.0
10
11 def setInterval(self, interval):
12 """Set the number of seconds we sleep between executing our task"""
13 self._interval = interval
14
15 def shutdown(self):
16 """Stop this thread"""
17 self._finished.set()
18
19 def run(self):
20 while 1:
21 if self._finished.isSet(): return
22 self.task()
23
24 # sleep for interval or until shutdown
25 self._finished.wait(self._interval)
26
27 def task(self):
28 """The task done by this thread - override in subclasses"""
29 pass
Exemplo de uso
1 # Nos exemplos assumirei que o módulo "cookbook" contém todos os códigos
2 from cookbook import TaskThread
3 from os.path import getsize
4
5 FILE = '/var/log/syslog'
6
7 class FileSizeTracker(TaskThread):
8 def __init__(self):
9 super(self, FileSizeTracker).__init__(self)
10 self._interval = 60.0 #segundos
11 self._lastsize = -1
12
13 def task(self):
14 size = getsize(FILE)
15 if size <> self._lastsize:
16 print 'O tamanho do arquivo agora é %d kilobytes (%d bytes)' % \
17 (round(size / 1024.0), size)
18 self._lastsize = size
19
20 if __name__ == '__main__':
21 print 'Checando a cada um minuto o tamanho do arquivo "%s".' % FILE
22 print 'Atenção: esse programa NUNCA termina.'
23 thread = FileSizeTracker()
24 thread.start()
25 thread.join()
Conclusão Final
Basicamente pode-se criar o seguinte caminho de perguntas e respostas:
1) Você tem algo contra o uso de classes?
- Se sim, utilize a primeira solução e tenha a certeza de que não vai ter a performance alterada.
- Se não, vá para a pergunta 2.
2) Você precisa criar algum tipo de controle avançado da função que será executada ou precisa de outras funcionalidades que só podem ser obtidas usando uma classe (como multiple inheritance)?
- Se sim, utilize a terceira solução. Com ela você cria a sua própria subclasse e pode reutilizá-la quantas vezes quiser.
- Se não, utilize a segunda solução. Esta solução provê uma interface igual à primeira solução porém sem o gargalo que pode vir a existir nesta última.
Volta para CookBook.