jv.batista Posted February 17, 2012 at 11:32 PM Report Share #440168 Posted February 17, 2012 at 11:32 PM Viva, Qual das duas opções é a melhor para correr varias funções ao mesmo tempo? Neste momento tenho várias threads a serem criadas consoante o numero de cpus(ver código abaixo) mas para além de não dever ser bem aquilo que quero a segunda só é criada depois de acabada a função que está na primeira thread. A função que está a ser chamada no exemplo é bastante rápida e até pode dispensar a utilização de threads/processos, no entanto as outras duas que tenho de usar já vão demorar bastante( actualmente, a segunda função, está a correr em cerca de 8h se não me engano ). Alguém sabe como é que posso resolver isto? Cumprimentos jv.batista edit: espero que não tenha confundido o pessoal. O que encontrei no forum era para C... class CreateAllStatistics(threading.Thread): objt = None thread = None cpuN = multiprocessing.cpu_count() forRange = {1 : [2000, 2011], 2 : [2000, 2005, 2011], 3 : [2000, 2003, 2007, 2011], 4 : [2000, 2002, 2005, 2008, 2011]} if(cpuN > 4): cpuN = 4 pass print cpuN def stop (self): global thread thread.kill() print "thread stopped" pass pass def start_thread (self): global thread for x in range (0, cpuN): print 'thread ' + str(x) + ' created!\n' initValue = forRange[cpuN][x] endValue = forRange[cpuN][x + 1] thread = KThread(target=self.start_cicle(initValue, endValue)) thread.start() pass pass def start_cicle(self, initValue, endValue): global objt objt = getStatistics() schoolQuantityTemp = {} for year in range(initValue, endValue): connection = sqlite3.connect('RebidesDBMulti.db') c = connection.cursor() c.execute(''' SELECT * FROM prof_data_year_{0} '''.format(year)) databaseContent = c.fetchall() c.close() schoolQuantityTemp[year] = (objt.getSchoolNamePerYear(year, databaseContent)) print len(schoolQuantityTemp[year]) pass #self.stop() pass pass def printResults(self): global schoolQuantity for key in schoolQuantity: print len(schoolQuantity[key]) pass pass Link to comment Share on other sites More sharing options...
djthyrax Posted February 17, 2012 at 11:56 PM Report Share #440172 Posted February 17, 2012 at 11:56 PM Vê se o link referido neste tópico que ajuda em alguma coisa: http://www.portugal-a-programar.pt/index.php?showtopic=37608 Não sei se o sistema se mantém no 3.0. Não peças ajuda por PM! A tua dúvida vai ter menos atenção do que se for postada na secção correcta do fórum! Link to comment Share on other sites More sharing options...
jv.batista Posted February 18, 2012 at 12:05 AM Author Report Share #440178 Posted February 18, 2012 at 12:05 AM Vê se o link referido neste tópico que ajuda em alguma coisa: http://www.portugal-a-programar.pt/index.php?showtopic=37608 Não sei se o sistema se mantém no 3.0. estou a usar o 2.7. Confirma-se a minha suspeição, vai ter mesmo de ser multiprocessing. Já estive de volta daquilo mas o idle acaba por crashar quando tentei criar 3 processos para fazer uma função simples que ia fazer um print do numero do processo umas quantas vezes... Cumps Link to comment Share on other sites More sharing options...
NuGuN Posted February 18, 2012 at 12:31 AM Report Share #440180 Posted February 18, 2012 at 12:31 AM Boas! Antes de começar, uma dica para a apresentação do post: Utiliza a ferramenta GeSHi para apresentares o teu código. Para o que queres fazer, eu aconcelho-te utilizares o modulo threading e esqueceres o multiprocessing. Bem, o teu código está um bocado confuso... Devias dar uma leitura num manual de python, funcionamento de classes, etc para melhor perceberes como vai funcionar o teu código uma vez que estás a derivar a tua classe. Ora bem, não sei ate que ponto faz sentido utilizares o número de CPU's existentes, uma vez que utilizando o modulo threading o "trabalho" vai ser distribuido automaticamente consuate os recursos. Portanto vamos deixar a parte do número de CPU's de parte. A estrutura que precisas é algo deste genero: class NomeAqui( threading.Thread ): def __init__( self ): # Definir aqui todos os objectos e atributos da classe def run( self ): # Colocar aqui o código que queres que a thread execute durante o seu tempo de vida if ( __name__ == "__main__" ): # Número de threads que queres criar threadNum = 4 # Lista para guardar as instâncias das classes criadas threadsList = [] # Crias uma instância da classe [i]NomeAqui[/i] para cada thread for i in range( 0, threadNum ): # Cria uma nova instância newThread = NomeAqui() # Adiciona a nova instância à lista threadsList.append( newThread ) # Depois de tudo criado está na altura de iniciar as threads criadas for thread in threadsList: # Este metodo "start" invoca o metodo "run" que foi criado na classe "NomeAqui" threads.start() Tenta agora adaptar o teu código a esta estrutura e vai colocando as dúvidas. Cumps! Link to comment Share on other sites More sharing options...
jv.batista Posted February 18, 2012 at 12:49 AM Author Report Share #440182 Posted February 18, 2012 at 12:49 AM Pois, digamos que é o ''primeiro'' programa que estou a fazer por isso é normal as coisas estarem um pouco à pedreiro... portanto, se percebi o que está ai, crio as threads primeiro, adiciono a um array e só depois é que faço start. Deixa lá ver no que é que é que isto vai dar... Link to comment Share on other sites More sharing options...
NuGuN Posted February 18, 2012 at 01:09 AM Report Share #440184 Posted February 18, 2012 at 01:09 AM Li o teu primeiro post com mais atenção e reparei na parte em que dizes que uma das execuções demora cerca de 8h... É muito processamento... O que te indiquei serve para coisas simples sem grande peso a nível de processamento. Devido a uma caracteristica de Python a eficiencia das threads deixa bastante a desejar e uma forma de contornar essa limitação seria realmente utilizar o modulo multiprocessing. Mas para ser sincero, com essa quantidade de informação para processar devias pensar em utilizar outra linguagem(C/C++) que não python e ias vez essas 8h reduzirem bastante... Para teres uma ideia da performance que podes ganhar fazendo isso em C/C++, à uns dias estive a fazer uns testes em que analisava pixel a pixel uma imagem de aproximandamente de 50x60. Fiz em python e em C, e entre outras coisas, o tempos de execução foram alguo deste tipo: - python: 4 segundos - C: < 1 segundo Bem, isto não é assim tão linear e varia muito com o que estás a trabalhar... Mas é certo que vais reduzir bem esse tempo se fizeres isso em C/C++... Cumps! Link to comment Share on other sites More sharing options...
jv.batista Posted February 18, 2012 at 01:24 AM Author Report Share #440187 Posted February 18, 2012 at 01:24 AM pois, eu por mim fazia isto em c/c++ mas como a cadeira exige que o trabalho seja feito em python lá tem de ser... é assim, a segunda função, recorrendo a um único for para percorre todos os anos(10), categorias de professores e escolas tem de fazer aproximadamente, 1494500000 iterações para cada ano( ~140 categorias, ~305 escolas, ~35000 professores num ano). a terceira função ainda vai adicionar mais um parâmetro a verificar( o grau do professor, licenciado, mestre ou doutor) e essa ainda vai demorar mais tempo. é por esta razão que queria dividir o for, fazendo assim com que conseguisse cortar o tempo pois estava a processar vários anos ao mesmo tempo. o que estava a tentar fazer também não é propriamente pedido, era apenas um 'extra' que queria adicionar pois permitia-me fazer todas as combinações de estatísticas para depois meter numa página html. vou antes fazer uma variação em que fixo um ou mais parâmetros, reduzindo assim o número de procuras... é que se tiver os parâmetros fixos, tipo o número de assistentes no ist no ano 2000 , a função é extremamente rápida. Link to comment Share on other sites More sharing options...
falco Posted February 18, 2012 at 12:33 PM Report Share #440213 Posted February 18, 2012 at 12:33 PM Não sei como é o estado da arte, mas em 2009 o Python não tinha threads reais, ou melhor, as threads que existiam no Python, não eram threads do kernel. O Python tem algo chamado Global Interpreter Lock (GIL), que na verdade impede que o Python aproveite realmente o hardware (por exemplo aproveitar multiplos cores do processador). O GIL é uma decisão de design do Guido e o Guido, não é conhecido como sendo uma pessoa que faz aquilo que acha ser errado (mesmo que haja quem ache que ele não tem razão e que lhe diga muitas vezes), como tal presumo que não hajam grandes mudanças... Ainda para mais ele já tentou remover o GIL uma vez e achou que resultou mal. O djthyrax, já mencionou um outro tópico aqui do fórum onde se diz isto (mas eu já tinha escrito e preferi reforçar). Se o motivo que tens para paralelizar com threads é aproveitar o hardware, então sugiro que não uses threads (ou não uses Python). Implementar threads é um assunto complicado e o Guido resolveu fazer este compromisso para garantir mais segurança. Outras linguagens como o Perl têm soluções diferentes (o Perl consegue aproveitar os multiplos processadores/cores), mas têm outras limitações. Outro problema em linguagens como o Perl e como o Python, é a diferença entre sistemas operativos (principalmente entre o window$ e os *nix). Link to comment Share on other sites More sharing options...
NuGuN Posted February 18, 2012 at 01:25 PM Report Share #440225 Posted February 18, 2012 at 01:25 PM Não sei como é o estado da arte, mas em 2009 o Python não tinha threads reais, ou melhor, as threads que existiam no Python, não eram threads do kernel. Pelo menos em windows e em Linux actualmente Python cria threads reais. O problema é mesmo o GIL... E é um problema tal que em determinadas situações um processamento em serie é mais rápido que paralelizando com threads... Cumps! Link to comment Share on other sites More sharing options...
jv.batista Posted February 18, 2012 at 02:32 PM Author Report Share #440232 Posted February 18, 2012 at 02:32 PM sim a ideia era usando o hardware disponível, fazer várias pesquisas ao mesmo tempo. Vou então fazer a coisa de outra forma, aproveitando a ideia da thread quando estou a gerar as estatísticas o programa não me bloquear tal como já tenho feito para o servidor html. Obrigado pela ajuda! Link to comment Share on other sites More sharing options...
falco Posted February 18, 2012 at 02:44 PM Report Share #440233 Posted February 18, 2012 at 02:44 PM Usa processos... Abre um socket (ou mais), usa ficheiros, ou algo do género e por exemplo serialização para partilhares os dados por esse meio de comunicação... Atenção que eu nem li o teu código, estou só a fazer sugestões genéricas... Alternativas à utilização de threads e variáveis partilhadas entre as threads... Link to comment Share on other sites More sharing options...
pedrotuga Posted February 18, 2012 at 06:56 PM Report Share #440251 Posted February 18, 2012 at 06:56 PM Sob o risco de soar um pouco arrogante, para o teu caso esta discussão toda sobre threads e processos no contexto de processadores multi-core é basicamente inútil. O que te está a empatar é entrada e saída de dados (IO), não é processamento. O teu processador tem tempo de ir ao café beber uma cerveja e voltar enquanto ligas abres e fechas ligações à tua base de dados. 1. Abre a ligação à base de dados uma vez e desliga-a só no fim. Não faz sentido fazer o que estar sempre a abrir e fechar e eu diria que é o que te está a demorar mais tempo. 2. Paraleliza mais, como te der mais jeito e de acordo com as características dos sistemas onde isto corre. Eu neste caso começaria logo por usar o modulo threading do python por ser o mais simples. E aumentaria o número de threads mesmo para 10 ou 20. Se tiveres memória com fartura usa o máximo que puderes, se o modulo de threading não te permitir fazer isto tanto quanto desejes, experimenta processos, ou as duas coisas. Eu não sei até que ponto é que tens liberdade para mudar isto, provavelmente o teu professor fez-te uma carrada de exigências. Mas ainda estou para perceber a utilidade (o sentido?) de uma aplicação que carrega dados 'on demand' de uma base de dados relacional convencinal por via de SQL e ao mesmo tempo tira partido de optimização de arquitecturas multi-core actuais. É como tentar quitar uma bicicleta com um motor de um ferrari. Link to comment Share on other sites More sharing options...
NuGuN Posted February 18, 2012 at 07:55 PM Report Share #440264 Posted February 18, 2012 at 07:55 PM É bem verdade que a abrir uma nova ligação a cada ciclo não ajuda muito, mas mesmo assim, tendo paralelização vai ter mais uma ligação por cada thread, logo não é completamente inútil. Mas tens toda a razão...esse pormenor passou-me despercebido. Cumps! Link to comment Share on other sites More sharing options...
jv.batista Posted February 18, 2012 at 08:50 PM Author Report Share #440266 Posted February 18, 2012 at 08:50 PM não é pelo facto de fazer a ligação à bd uma vez por ano que o programa se torna lento. para os 10 anos estamos a falar de ~3s no tempo de execução do programa. o problema está mesmo na quantidade de vezes que tenho de percorrer a lista resultante do pedido à bd. para a situação apontada o programa corre em pouco mais de 3s. o problema está quando tem de fazer algo assim : def getTeacherNumberCategoryEstablismentYear(self, year, schoolName, profCategory, databaseContent): profs = {} position = 0 for line in databaseContent: if(schoolName == line[8].encode('utf-8')): if(profCategory == line[4].encode('utf-8')): position = len(profs) profs[position] = line[1].encode('utf-8') pass pass pass pass return profs ou assim: def getTeacherNumberDegreeTypeEstablismentYearCategory(self, year, schoolName, degreeType, profCategory, databaseContent): profs = {} position = 0 for line in databaseContent: if(schoolName == line[8].encode('utf-8')): if(degreeType == line[2].encode('utf-8')[0]): if(profCategory == line[4].encode('utf-8')): position = len(profs) profs[position] = line[1].encode('utf-8')) pass pass pass pass pass return profs deixo aqui a forma como estou a fazer a primeira função para todos os anos: for year in range (2000, 2011): connection = sqlite3.connect('RebidesDBMulti.db') c = connection.cursor() c.execute(''' SELECT * FROM prof_data_year_{0} '''.format(year)) databaseContent = c.fetchall() c.close() escolas = obj.getSchoolNamePerYear(year, databaseContent) categorias = obj.getCategoryNamePerYear(year, databaseContent) for categoria in categorias: for escola in escolas: dicProfs = obj.getTeacherNumberCategoryEstablismentYear(year, escola, categoria, databaseContent) dicCat[categoria] = dicProfs pass dicEscola[escola] = dicCat pass dicAno[year] = dicEscola pass ps: agora estava aqui a ver e sou capaz de ganhar algum tempo se for procurar apenas pelas categorias existentes numa certa escola em vez de ir procurar por todas as categorias existentes num ano... algo tipo isto: for year in range (2000, 2011): connection = sqlite3.connect('RebidesDBMulti.db') c = connection.cursor() c.execute(''' SELECT * FROM prof_data_year_{0} '''.format(year)) databaseContent = c.fetchall() c.close() escolas = obj.getSchoolNamePerYear(year, databaseContent) for escola in escolas: categorias = {} for line in databaseContent: if(escola== line[8].encode('utf-8')): posicao = len(categorias) categorias[posicao] = line[4].encode('utf-8') for categoria in categorias: dicProfs = obj.getTeacherNumberCategoryEstablismentYear(year, escola, categoria, databaseContent) dicCat[categoria] = dicProfs pass dicEscola[escola] = dicCat pass dicAno[year] = dicEscola pass Link to comment Share on other sites More sharing options...
djthyrax Posted February 18, 2012 at 08:54 PM Report Share #440269 Posted February 18, 2012 at 08:54 PM Não consegues fazer com que o servidor MySQL faça mais trabalho? É que uma query do tipo SELECT * FROM tabela não me parece de todo optimizada. Não peças ajuda por PM! A tua dúvida vai ter menos atenção do que se for postada na secção correcta do fórum! Link to comment Share on other sites More sharing options...
jv.batista Posted February 18, 2012 at 09:03 PM Author Report Share #440271 Posted February 18, 2012 at 09:03 PM Não consegues fazer com que o servidor MySQL faça mais trabalho? É que uma query do tipo SELECT * FROM tabela não me parece de todo optimizada. é a unica query que posso fazer à base de dados. toda a obtenção dos dados tem de ser feita em python Link to comment Share on other sites More sharing options...
jv.batista Posted February 18, 2012 at 09:41 PM Author Report Share #440279 Posted February 18, 2012 at 09:41 PM bom, parece-me que a alteração que fiz meteu-me o ciclo para um ano a demorar 77segundos... se for assim, estamos a falar de 770 para os 10 anos. edit: depois de 880 segundos tenho os resultados. aquela pequena alteração conseguiu poupar paletes de tempo... edit2: voltei a alterar o método e em vez de percorrer a lista com base de dados referente a um ano, passei a percorrer uma lista com apenas os dados referentes à escola em questão no ciclo e consegui passar dos 880 segundos para os 113.71. Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now