Threads em python não precisam ser chatas, descobri hoje!Há tempos que tento entender isso. Usei no pyBaixador de Trabalho quase o mesmo codigo que mostrarei agora, só que não entendia bem o que estava acontecendo…
Primeiro é necessário entender o que é um decorator.
Em python é possível fazer com que uma função “decore” a outra, sendo assim, quando uma função for chamada, outra função atua sobre ela como uma espécia de interface. A sintaxe é simples.
Veja:
[python]
def decorador(funcao):
print “O nome da funcao decorada eh:”, funcao.__name__
print funcao.__dict__
print funcao.__doc__
return funcao
@decorador
def printer(string=”OLA MUNDO”):
“”"
Essa funcao imprime na tela o valor dado
“”"
print string
[/python]
Note que o “@” em @decorador é o que determina que a função decorador atuará como um decorator. E sintáticamente ele deve estar acima da função a ser decorada, no caso é a função printer.
Parece difícil, mas é fácil olhando dessa forma!
Vamos chamar a função decorada:
[python]
printer()
[/python]
Resulta em:
[code]
O nome da funcao decorada eh: printer
{}
Essa funcao imprime na tela o valor dado
OLA MUNDO
[/code]
Sendo assim podemos escrever um decorator que funcione como fábrica de threads:
[python]
import threading
def threaded(funcao):
def wrapper(*args):
t = threading.Thread(target=funcao, args=args)
t.setDaemon(True)#se True, o script sai sem esperar pela thread
t.start()
wrapper.__name__ = funcao.__name__
wrapper.__dict__ = funcao.__dict__
wrapper.__doc__ = funcao.__doc__
return wrapper
@threaded
def infinito():
import time
while True:
print “Estou numa thread!\n\nPressione ENTER para continuar”
time.sleep(1)
infinito()
raw_input()
[/python]
A idéia é simples, mas como faço para aplicar isso em pygtk?
O GTK é bem tranqüilo para trabalhar com threads pois é thread-safe. Basta usarmos seus métodos especiais:
gtk.gdk.threads_init() - no inicio do codigo
e
gtk.gdk.threads_leave() - no final do codigo, mas antes do gtk.main()
esse métodos especiais fazem interação com o mainloop do gtk atuando no semáforo.
A seguir um exemplo na íntegra de como se faz:
[python]
#!/usr/bin/python
# -*- coding: utf-8 -*-
import gtk,sys,gobject,time
import threading,thread
def threaded(f):
def wrapper(*args):
t = threading.Thread(target=f, args=args)
t.setDaemon(True)#se true o programa sai sem esperar pela thread
t.start()
wrapper.__name__ = f.__name__
wrapper.__dict__ = f.__dict__
wrapper.__doc__ = f.__doc__
return wrapper
def sair(widget):
sys.exit(0)
@threaded
def tim(*args):
gtk.gdk.threads_init()
print “entrei no tim”
for iteration in reversed(xrange(1,11)):
print “iterando…”,iteration
texto.set_markup(”%d” % iteration)
time.sleep(1)
texto.set_markup(”BOOOM!“)
gtk.gdk.threads_leave()
janela=gtk.Window()
janela.set_default_size(300,300)
janela.connect(’destroy’,sair)
janela.set_title(”Threads do bem!”)
box=gtk.VBox()
texto=gtk.Label()
texto.set_markup(”CLIQUE!“)
texto.show()
box.pack_start(texto)
btn=gtk.Button(”Clicaqui!”)
btn.show()
btn.connect(”clicked”,tim)
box.pack_start(btn,False,False)
box.show()
janela.add(box)
janela.show()
gtk.gdk.threads_init()
gtk.main()
[/python]
Walter, valeu mais uma vez pela ajuda no entendimento
Referência