Novamente, estou sem a documentacao aqui para checar com mais
precisao, mas vou dar mais um palpite. Note que, se o resulta-
do com e sem o uso de threads eh o mesmo (como voce disse na
sua mensagem), entao provavelmente eh porque voce esta perden-
do o efeito do uso das threads de alguma maneira. Aqui vai o
meu palpite:
---
> def ThreadBacen(self, dia, mes, ano):
> #threads = []
> for page in self.BacenTaxas:
> t = threading.Thread(target=self.getBacen, args=(dia,
> mes, ano, page))
> t.start()
> t.join()
---
Se bem me lembro, o metodo '.join' diz para o thread atual es-
perar a segunda thread completar seu processamento para poder
continuar executando. 'Join' significaria justamente colocar
uma thread esperando outra se juntar a ela. A GUI pode estar
travando exatamente por causa dessa espera. Voce nao pode ti-
rar o join para nao ter uma catastrofe com suas threads, mas
acredito que eh aih que esta o problema. Basicamente, o trecho
---
t.start()
t.join()
---
eh uma 'chamada' para o metodo self.getBacen, e a thread atual
fica esperando o fim do processamento - e soh depois disso eh
que sua rotina parte para a inicializacao de outra thread. O
resultado nao eh muito diferente de uma chamada padrao a um me-
todo, e o efeito do uso de threads desaparece.
Veja que no codigo que voce comentou, todas as threads sao ini-
cializadas e apenas _depois_ disso eh que se faz o join. No seu
codigo, cada thread eh inicializada e 'juntada' uma a uma. Por-
tanto, nao ha o beneficio de se ter threads: cada uma delas eh
executada separadamente. Tente adaptar o codigo comentado ao seu,
e acredito que tudo funcionara perfeitamente. Ou, pelo menos, com
problemas diferentes. :)
(Veja se o seguinte trecho funciona):
---
threadlist = []
for page in self.BacenTaxas:
t = threading.Thread(target=self.getBacen,
args=(dia, mes, ano, page))
t.start()
threadlist.append(t)
for t in threadlist:
t.join()
---
Nao tive como testar, mas me parece correto.
---
Jose Alexandre Nalon
na...@terra.com.br
* Antes de enviar a sua pergunta procure por uma solução em:
http://pythonbrasil.com.br/
http://python.org
http://google.com
* Não envie e-mails HTML para a lista.
* Evite mensagens off-topic
Links do Yahoo! Grupos
<*> Para visitar o site do seu grupo na web, acesse:
http://br.groups.yahoo.com/group/python-brasil/
<*> Para sair deste grupo, envie um e-mail para:
python-brasi...@yahoogrupos.com.br
<*> O uso que você faz do Yahoo! Grupos está sujeito aos:
http://br.yahoo.com/info/utos.html
#___________________________________________________________________
def ThreadBacen(self, dia, mes, ano):
#threads = []
for page in self.BacenTaxas:
t = threading.Thread(target=self.getBacen, args=(dia,
mes, ano, page))
t.start()
t.join()
#A estrutura abaixo eu vi no exemplo, eu achei ruim, a que
implementei
#achei melhor
#num = len(threads)
#for index in range(num):
# threads[index].start()
#Aqui eu preciso esperar todos os threads acabarem
#for index in range(num):
# threads[index].join()
#--------------------------------
for page in self.BacenTaxas:
self.SawTables(page, dia, mes, ano)
self.LogWrite("Tabelas processadas...Processo completo")
self.JoinAndShow()
#____________________________________________________________________
Resto do código (espero que não perca a formatação!!!)
#Boa:Frame:wxFrame1
import os, urllib, time, string, threading
from wxPython.wx import *
from wxPython.stc import *
def create(parent):
return wxFrame1(parent)
[wxID_WXFRAME1, wxID_WXFRAME1ANBID, wxID_WXFRAME1ANDIMA,
wxID_WXFRAME1BACEN,
wxID_WXFRAME1BMF, wxID_WXFRAME1BOVESPA, wxID_WXFRAME1BTNBUSCARTAXAS,
wxID_WXFRAME1BTNCLEAN, wxID_WXFRAME1OUTPUT,
wxID_WXFRAME1STATICTEXT1,
wxID_WXFRAME1TXTDATA,
] = map(lambda _init_ctrls: wxNewId(), range(11))
class wxFrame1(wxFrame):
def _init_utils(self):
# generated method, don't edit
pass
def _init_ctrls(self, prnt):
# generated method, don't edit
wxFrame.__init__(self, id=wxID_WXFRAME1, name='', parent=prnt,
pos=wxPoint(360, 220), size=wxSize(433, 403),
style=wxDEFAULT_FRAME_STYLE,
title='WebCrawler Luz Engenharia Financeira')
self._init_utils()
self.SetClientSize(wxSize(425, 376))
self.SetForegroundColour(wxColour(192, 192, 192))
self.SetBackgroundColour(wxColour(192, 192, 192))
self.bacen = wxCheckBox(id=wxID_WXFRAME1BACEN, label=u'Bacen',
name=u'bacen', parent=self, pos=wxPoint(16, 16),
size=wxSize(73,
13), style=0)
self.bacen.SetValue(False)
self.bmf = wxCheckBox(id=wxID_WXFRAME1BMF, label=u'BMF',
name=u'bmf',
parent=self, pos=wxPoint(16, 40), size=wxSize(73, 13),
style=0)
self.bmf.SetValue(False)
self.bovespa = wxCheckBox(id=wxID_WXFRAME1BOVESPA,
label=u'Bovespa',
name=u'bovespa', parent=self, pos=wxPoint(16, 63),
size=wxSize(73,
13), style=0)
self.bovespa.SetValue(False)
self.andima = wxCheckBox(id=wxID_WXFRAME1ANDIMA,
label=u'Andima',
name=u'andima', parent=self, pos=wxPoint(16, 85),
size=wxSize(73,
13), style=0)
self.andima.SetValue(False)
self.BtnBuscarTaxas = wxButton(id=wxID_WXFRAME1BTNBUSCARTAXAS,
label=u'Buscar taxas', name=u'BtnBuscarTaxas',
parent=self,
pos=wxPoint(16, 305), size=wxSize(81, 23), style=0)
EVT_BUTTON(self.BtnBuscarTaxas, wxID_WXFRAME1BTNBUSCARTAXAS,
self.OnBtnbuscartaxasButton)
self.TxtData = wxTextCtrl(id=wxID_WXFRAME1TXTDATA,
name=u'TxtData',
parent=self, pos=wxPoint(104, 16), size=wxSize(100,
21), style=0,
value=u'')
self.staticText1 = wxStaticText(id=wxID_WXFRAME1STATICTEXT1,
label=u'Data no formato dd/mm/aaaa', name='staticText1',
parent=self, pos=wxPoint(214, 16), size=wxSize(172,
13), style=0)
self.staticText1.SetFont(wxFont(8, wxSWISS, wxNORMAL,
wxNORMAL, False,
u'Verdana'))
self.staticText1.SetForegroundColour(wxColour(0, 0, 0))
self.Output = wxStyledTextCtrl(id=wxID_WXFRAME1OUTPUT,
name=u'Output',
parent=self, pos=wxPoint(104, 48), size=wxSize(288,
316),
style=0)
self.BtnClean = wxButton(id=wxID_WXFRAME1BTNCLEAN,
label=u'Limpar Diret\xf3rio', name=u'BtnClean',
parent=self,
pos=wxPoint(16, 339), size=wxSize(82, 23), style=0)
EVT_BUTTON(self.BtnClean, wxID_WXFRAME1BTNCLEAN,
self.OnBtncleanButton)
self.anbid = wxCheckBox(id=wxID_WXFRAME1ANBID, label=u'Anbid',
name=u'anbid', parent=self, pos=wxPoint(16, 106),
size=wxSize(73,
13), style=0)
self.anbid.SetValue(False)
def __init__(self, parent):
self._init_ctrls(parent)
self.Output.SetText("Processo aberto")
#Parametros que podem ser alterados
self.dir = "c:\\webdata"
try:
os.chdir(self.dir)
except:
os.mkdir(self.dir)
os.chdir(self.dir)
self.bmfurl = "http://www.bmf.com.br/arquivos1/download.asp"
self.bacenurl
= "http://www4.bcb.gov.br/pec/series/port/apresentadados.asp"
self.BacenTaxas = {"TR": 226, "TRproRata": 227, "TBF":
253, "TBFproRata": 254, "Selic": 1178}
self.andimaurl = "http://www.andima.com.br/merc_sec/arqs/"
self.bovespaurl = "http://www.bovespa.com.br/bdi/"
self.anbidurl = "http://www.anbid.com.br/taxa_anbid/TxDia.pdf"
#-------------------------------------------------------------
--
#Nao toque aqui, imbecil...
self.Months = {1:"jan", 2:"fev", 3:"mar", 4:"abr", 5:"mai",
6:"jun",
7:"jul", 8:"ago", 9:"set", 10:"out", 11:"nov", 12:"dez"}
self.Days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
def ValidaData(self, data):
Days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
biYear = []
First = 1900
for x in range(1, 40):
First += 4
biYear.append(First)
tam = len(data)
dia = data[0:2]
mes = data[3:5]
ano = data[6:10]
#Teste de tamanho
if (tam!=10):
self.ShowErros('Sua data est\xe1 errada! No m\xednimo 10
caracteres')
return -1, dia, mes, ano
#Anos bissextos e datas invalidas
if (int(ano) in biYear):
Days[1] = 29
#Validacao das datas
if (int(ano) < 2000):
self.ShowErros('Data muito antiga, tente uma mais
recente')
return -1, dia, mes, ano
if (int(mes) > 12):
self.ShowErros('N\xf3s, terr\xe1queos, s\xf3 usamos 12
meses!')
return -1, dia, mes, ano
MaxPossible = Days[int(mes)-1]
if (int(dia) > MaxPossible):
self.ShowErros('Verifique qual o maior dia para esse
m\xeas')
return -1, dia, mes, ano
return 1, dia, mes, ano
def ShowErros(self, msg):
dlg = wx.wxMessageDialog(self, msg,'Aviso',
wxOK | wxICON_INFORMATION)
dlg.ShowModal()
dlg.Destroy()
def LogWrite(self, msg):
self.Output.SetText(self.Output.GetText()+"\n"+msg)
def getBmf(self, dia, mes, ano):
data = dia+"/"+mes+"/"+ano
taxas =
{"C1":"ON", "T1":data, "C2":"ON", "T2":data, "C3":"ON", "T3":data,
"C7":"ON", "T7":data, "C9":"ON", "T9":data}
params = urllib.urlencode(taxas)
site = urllib.urlopen(self.bmfurl, params)
arquivo = open("bmf.exe", "wb")
stream = site.read()
arquivo.write(stream)
arquivo.close()
os.system("bmf.exe")
os.remove("bmf.exe")
self.LogWrite("Arquivo BMF descompactado")
def getBacen(self, dia, mes, ano, seriesName):
'Busca uma serie em particular do BaCen'
self.LogWrite("Started "+ seriesName + " at " + time.ctime
(time.time()))
series = self.BacenTaxas[seriesName]
diaini, mesini, anoini = self.DiffDatas(dia, mes, ano, 5)
diafim, mesfim, anofim = dia, mes, ano
web = {"series": series, "diaini": diaini, "mesini": mesini,
"anoini": anoini, "diafim": diafim, "mesfim": mesfim,
"anofim": anofim, "opcDownload": 1}
params = urllib.urlencode(web)
site = urllib.urlopen(self.bacenurl,params)
arqu = open(seriesName + ".htm", "w")
arqu.write(site.read())
arqu.close()
self.LogWrite("Ended " + seriesName + " at " + time.ctime
(time.time()))
def ThreadBacen(self, dia, mes, ano):
#threads = []
for page in self.BacenTaxas:
t = threading.Thread(target=self.getBacen, args=(dia,
mes, ano, page))
t.start()
t.join()
#A estrutura abaixo eu vi no exemplo, eu achei ruim, a que
implementei
#achei melhor
#num = len(threads)
#for index in range(num):
# threads[index].start()
#Aqui eu preciso esperar todos os threads acabarem
#for index in range(num):
# threads[index].join()
#--------------------------------
for page in self.BacenTaxas:
self.SawTables(page, dia, mes, ano)
self.LogWrite("Tabelas processadas...Processo completo")
self.JoinAndShow()
def DiffDatas(self, dia, mes, ano, diff):
'Calcula a diferenca em dias corridos da data atual para uma
anterior, dado o numero de dias'
dia, mes, ano, diff = int(dia), int(mes), int(ano), int(diff)
biYear = []
First = 1900
for x in range(1, 40):
First += 4
biYear.append(First)
dia = dia - diff
while(dia <= 0):
mes = mes - 1
if (mes == 0):
mes = 12
ano -= 1
EndMonth = self.Days[mes-1]
if(self.Months[mes] == "fev" and (ano in biYear)):
EndMonth += 1
dia = EndMonth+dia
if (dia <10): dia = "0"+ str(dia)
if (mes <10): mes = "0"+ str(mes)
return str(dia), str(mes), str(ano)
def SawTables(self, serie, dia, mes, ano):
'Apaga todo o HTML em torno da tabela que possui cotacoes'
Tables, Text = self.IndentifyTables(serie)
Dates = []
for i in range(1, 7):
Dates.append(self.DiffDatas(dia, mes, ano,
i))
Ranking = []
FilterTables = []
for item in range(len(Tables)):
Raw = []
FirstRow, FirstCol = Tables[item][0][0], Tables[item][0]
[1]
LastRow, LastCol = Tables[item][1][0], Tables[item][1][1]
Raw.append(Text[FirstRow][FirstCol:])
for i in range(FirstRow+1, LastRow-1):
Raw.append(Text[i])
Raw.append(Text[LastRow][:LastCol+8])
match = 0
for lines in Raw:
for dia in Dates:
BrazilDay = dia[0]+"/"+dia[1]+"/"+dia[2]
find = string.find(lines, BrazilDay)
if (find !=-1):
match+=1
Ranking.append(match)
FilterTables.append(Raw)
maior = Ranking[0]
for i in range(len(Ranking)-1):
if maior < Ranking[i]:
maior = Ranking[i]
index = i
arqu = open(serie+".htm", "w")
arqu.write(FilterTables[index][0])
arqu.close()
return Ranking, FilterTables
def IndentifyTables(self, arquivo):
'Organiza em tuplas as coordenadas (linha, coluna) da
abertura e do fechamento da table'
StartTables, Text = self.FindPattern(arquivo, "<table")
EndTables, Text = self.FindPattern(arquivo, "</table>")
NewStart = []
NewEnd = []
Tables = []
Iterations = len(StartTables)
for element in StartTables:
NewStart.append((element, 1))
for element in EndTables:
NewEnd.append((element, 0))
TotalTables = NewStart + NewEnd
TotalTables.sort()
next=1
pos=0
while(Iterations > 0):
while(TotalTables[pos][1]!= 1):
pos+=1
while(TotalTables[pos+next][1]!= 0):
next+=1
if (next == 1):
itens = (TotalTables[pos], TotalTables[pos+next])
Tables.append((itens[0][0],itens[1][0]))
TotalTables.remove(itens[0])
TotalTables.remove(itens[1])
Iterations-=1
next=1
pos=0
else:
pos+=1
next=1
return Tables, Text
def FindPattern(self, arquivo, tag):
'Identifica a abertura e o fechamento de uma tag de html, ex:
<table></table>'
import string
arqu = open(arquivo + ".htm", "r")
Text = []
NewText = []
TablesPos = []
for lines in arqu:
Text.append(lines)
arqu.close()
TotalLines = len(Text)
for row in range(TotalLines):
lowcaps = string.lower(Text[row])
lowcaps = string.strip(lowcaps)
NewText.append(lowcaps)
init = 0
while (string.find(lowcaps[init:], tag) != -1):
pos = string.find(lowcaps[init:], tag)
TablesPos.append((row, pos+init))
init += pos+4
return TablesPos, NewText
def JoinAndShow(self):
'Apenas integra as taxas para visualizacao'
AllHtml = []
for pages in self.BacenTaxas:
arq = open(pages+".htm", "r")
AllHtml.append(arq.read())
arq.close()
NewHtml = ""
for item in AllHtml:
NewHtml += item + "<br>\n"
arq = open("join.htm", "w")
arq.write(NewHtml)
arq.close
self.LogWrite("Tabelas unificadas")
def getAndima(self, dia, mes, ano):
ano = ano[2:4]
mes = self.Months[int(mes)]
arqu = "m" + str(ano) + mes + str(dia) + ".exe"
site = urllib.urlopen(self.andimaurl+arqu)
save = open("andima.exe", "wb")
save.write(site.read())
save.close()
os.system("andima.exe")
os.remove("andima.exe")
self.LogWrite("Arquivo Andima descompactado:\n " +
self.andimaurl+arqu)
def getBovespa(self, dia, mes, ano):
ano = ano[2:4]
arqu = "bdi" +str(dia)+str(mes)+ ".zip"
site = urllib.urlopen(self.bovespaurl+arqu)
save = open("bovespa.zip", "wb")
save.write(site.read())
save.close()
dirlist = os.listdir(self.dir)
if 'BDIN' in dirlist:
os.remove('BDIN')
os.system("pkunzip bovespa.zip")
os.remove("bovespa.zip")
self.LogWrite("Arquivo Bovespa descompactado:\n " +
self.bovespaurl+arqu)
def ClearOutput(self):
self.Output.SetText("")
def getAnbid(self, dia, mes, ano):
site = urllib.urlopen(self.anbidurl)
arqu = open("anbid.pdf", "wb")
arqu.write(site.read())
arqu.close()
os.system("pdftohtml anbid.pdf")
os.remove("anbid.html")
os.remove("anbid_ind.html")
os.remove("anbid.pdf")
self.MountAnbidHtml(dia, mes, ano)
self.LogWrite("Download do arquivo Anbid efetuado")
def MountAnbidHtml(self, dia, mes, ano):
arqu = open("anbids.html")
Lines = []
Datas = []
NewArray = []
for x in range(30):
sdia, smes, sano = self.DiffDatas(dia, mes, ano, x)
diacomp = sdia + "/" + smes + "/" + sano
Datas.append(diacomp)
for linha in arqu:
Lines.append(linha)
count = len(Lines)
index = 0
while(index < count):
Mystr = Lines[index]
data = Mystr[:10]
if data in Datas:
diasCorr = Lines[index+1][:-5]
diasUteis = Lines[index+2][:-5]
txanual = Lines[index+3][:-5]
txefetiva = Lines[index+4][:-5]
NewArray.append((data, diasCorr, diasUteis, txanual,
txefetiva))
index+=5
else:
index+=1
arqu.close()
newArqu = open("anbid.html", "w")
newArqu.write("<table border=1><tr><td>data</td><td>Dias
DC</td><td>Dias Uteis</td>"+
"<td>Taxa Anual</td><td>Taxa Efetiva</td></tr>")
count = len(NewArray)
for x in range(count):
linha = "<tr><td>" + NewArray[x][0] + "</td><td>" +
NewArray[x][1]+ "</td><td>" + NewArray[x][2] + "</td><td>" + NewArray
[x][3] + "</td><td>" + NewArray[x][4] + "</tr>"
newArqu.write(linha)
newArqu.write("</table>")
os.remove("anbids.html")
newArqu.close()
def OnBtncleanButton(self, event):
self.ClearOutput()
lista = os.listdir(self.dir)
lista.remove("pkunzip.exe")
lista.remove("pdftohtml.exe")
Pages = []
for element in lista:
os.remove(element)
Pages.append(element)
self.LogWrite("Itens apagados:")
for Arqu in Pages:
self.LogWrite(str(Arqu))
def OnBtnbuscartaxasButton(self, event):
import threading
import os
self.ClearOutput()
Primeiro = self.bacen.GetValue()
Segundo = self.bmf.GetValue()
Terceiro = self.andima.GetValue()
Quarto = self.bovespa.GetValue()
Quinto = self.anbid.GetValue()
Verify, dia, mes, ano = self.ValidaData(self.TxtData.GetValue
())
if (Verify == -1):
return 0
if (Primeiro):
self.ThreadBacen(dia, mes, ano)
if (Segundo):
self.getBmf(dia, mes, ano)
if (Terceiro):
self.getAndima(dia, mes, ano)
if (Quarto):
self.getBovespa(dia, mes, ano)
if (Quinto):
self.getAnbid(dia, mes, ano)
> Valeu pela força, mas se vc reparar nos comentários estava exatamente
> como sugeriu, que é o exemplo padrão usando o módulo.
> Já experimentei sem o join também, e não funcionou. Aí eu separaria
> os outros procedimentos para depois.
> Eu criava os threads e colocava na lista, depois em outro loop
> iniciava eles, e finalmente no último loop o join.
Você fala disso aqui?
def ThreadBacen(self, dia, mes, ano):
threads = []
for page in self.BacenTaxas:
t = threading.Thread(target=self.getBacen, args=(dia,
mes, ano, page))
num = len(threads)
for index in range(num):
threads[index].start()
#Aqui eu preciso esperar todos os threads acabarem
for index in range(num):
threads[index].join()
#--------------------------------
for page in self.BacenTaxas:
self.SawTables(page, dia, mes, ano)
self.LogWrite("Tabelas processadas...Processo completo")
self.JoinAndShow()
(...)
Esse exemplo comentado que você colocou não resolve o
problema simplesmente porque você não está trabalhando
com o wxPython. Você precisa mudar o estilo do seu
programa para considerar que há um loop principal que
coleta eventos disparados *durante* a execução e busca
dos dados em outras threads. Não é a toa que o UI
trava, você não deixa ele atualizar os eventos recebidos
(redefinir tamanho, redesenhar a tela, clicar do mouse
etc).
Uma sugestão: invoque as threads em uma função e pegue
as informações delas em outra.
class ThreadCtl:
_threads = []
# Dispara todas as threads.
def StartThreads(self, dia, mes, ano):
for page in self.BacenTaxas:
t = threading.Thread(target = self.getBacen, args = (dia, mes, ano,
page))
self._threads.append(t)
t.start()
# Função que desabilita todas os widgets dependentes dos
# dados que precisam antes ser lidos.
self.DisableUserInput()
# Volta para MainLoop()
return
# Função que atualiza a tela com os dados lidos depois que todas
# as threads acabaram suas tarefas.
def GotData(self):
# Atualiza os dados na tela.
self.update()
# Ativa a entrada do usuário.
self.EnableUserInput()
# Volta para MainLoop()
return
Espero que isso ajude.
[]'s!
Pedro
--
Home: http://www.nonseq.net | Blog: http://www.nonseq.net/?q=blog/1
ICQ: 2878740 | Orkut: "Pedro" (nome) "De Medeiros" (sobrenome)
___________________________________________
Yawl Internet http://www.yawl.com.br/
Acesso Discado / ADSL / 24Hs
Hospedagem ASP, PHP, JSP, ColdFusion, MySQL
> Agora faltou sinapse aqui, eu simplesmente começo o thread com start?
> Mas isso fora da classe que define a gui, não é? Como GotData vai
> saber que os threads foram executados?
Você pode colocar o código que gera as threads onde quiser,
contanto que executem no thread principal e este manterá
registro delas. Isso depende mais de como é a sua implemen-
tação das classes. Faça o que for mais consistente pra você
e a forma que você adotou, mas acho melhor você usar a
implementação de threads do próprio wxPython (wxThreads),
porque, afinal, faz parte da biblioteca e nenhuma outra foi
melhor testada.
Uma função que testa se as outras threads acabaram seria
algo assim:
def WaitThreads(self):
for thread in self._threads:
if thread.IsAlive(): thread.join()
(continua...)
Que poderia ser inclusive uma outra thread (que não está
dentro de self._threads, afinal você não quer causar um
deadlock fazendo um thread esperar por si mesmo). Essa
função pode então chamar self.GotData ou mandar um aviso
para o thread principal fazê-lo. Portanto, fique de olho
se isso é seguro de se realizar de outra thread. Existem
funções de sincronização que asseguram que o thread atual
é o único thread manipulando dados de widgets do wxPython
(não lembro o nome). Afinal, pode haver condições de
corrida com dados sendo alterados ao mesmo tempo. Aconselho
usá-las.
Até!
> A documentação sugere usar o módulo threading, mas acho que para esse
> caso terei que usar thread mesmo, como no exemplo que vem no wxPython.
Nesse caso, consulte a documentacao do wxPython para verificar
se voce nao estah utilizando alguma funcao que nao eh thread-
safe. Utilizar threads, em geral, eh algo bastante complicado,
verifique se seu codigo nao estah fazendo acesso a algum recur-
so que nao fica sempre disponivel. Nesse caso, uma thread pode
travar a outra e aih jah viu. Eh possivel que voce precise uti-
lizar Events ou Semaphores para controlar esses acessos e tudo
mais.
Tambem nao tenho a documentacao do wxPython aqui, mas creio que
ele implemente filas de eventos (que toolkit nao faz isso?) que
provavelmente voce pode utilizar _sem_ ter que recorrer a threads.
Possivelmente, isso vai dar melhores resultados. Mas nao conheco
bem o wxPython nesse caso para poder recomendar (mas posso reco-
mendar para voce _nao_ misturar em hipotese nenhuma duas implemen-
tacoes diferentes de threads _ou_ de toolkits - isso em geral ge-
ra muuuuuuita confusao).
---
Jose Alexandre Nalon
na...@terra.com.br