2012/12/9 Aureliano Guedes <guedes_1...@hotmail.com>: > Breno, so uma duvida, antigamente eu usava muito arquivos temporario, eu > deixei de usar pois achava que perdia muito em performance. > > Você acha que eu perco muito em performance usando a solução 4 no lugar das > outras soluções? >
Resposta brevíssima: não importa. Pronto. Pode parar de ler aqui. É sério. Se, por alguma curiosidade mórbida, vc quiser mais detalhes, continue lendo :) Como a maioria das coisas do mundo, depende. Se você tiver RAM infinita, manter tudo em memória é sempre muito mais rápido do que fazer acessos ao disco. Para saber mais: https://en.wikipedia.org/wiki/Space-time_tradeoff No entanto, há casos em que você *quer* armazenar dados em arquivos temporários, não só por questões de memória, mas também para ter estados intermediários em sua execução. Ou quando, como no exemplo anterior, vc quer transformar um arquivo em outro. Afinal, pense comigo: se vc vai ler um arquivo de entrada e escrever num arquivo de saída, pq precisa que seja o mesmo arquivo? Preservar o arquivo original pode te ajudar não só na simplicidade do código como nos casos em que você quer validar os resultados repetindo a execução, ou depurar seu programa caso algo estranho esteja acontecendo. Sem o original intacto, como recuperá-lo? Você provavelmente está guardando cópia do arquivo original em algum lugar (por esses mesmos motivos) então pq não oficializar a coisa e gravar a saída processada em outro arquivo (que portanto deixa de ser temporário)? Vejamos as operações envolvidas no problema. Sem arquivos temporário, temos os seguintes passos: 1) ler o arquivo todo do disco para memória 2) processar os dados 3) voltar a posição do handle para o início do arquivo 4) escrever o arquivo no disco 5) truncar o restante Já com arquivos temporários, temos: 1) ler o arquivo do disco para memória 2) processar os dados 3) escrever o arquivo novo no disco 4) renomear arquivo no disco para substituir original (se não for usar) Otimizações à parte, o processo em si é bastante parecido, com uma ação de leitura e outra de escrita (ok, duas se rolar o rename, mas não é lá uma grande operação de E/S), então não deve fazer lá grandes diferenças em termos de desempenho. Antes de continuar, esqueci de colocar na resposta anterior uma outra solução entre a 4 e a 5, vamos chamá-la de 4.5: ----------8<----------- #!/usr/bin/env perl use strict; use warnings; use autodie; my $nome_original = 'arquivo.txt'; open my $orig_fh, '<', $nome_original; my @linhas; my $i = 0; while ( my $linha = <$orig_fh> ) { if ($linha =~ s/^>.+$/>contig$i/ ) { $i++; } } continue { push @linhas, $linha; } close $orig_fh; open $orig_fh, '>', $nome_original; print $orig_fh @linhas; close $orig_fh; ---------->8----------- Essa solução tem duas diferenças em relação à 4. Aqui, estamos acumulando os dados processados em memória (na variável @linhas) e, após o processamento, reabrimos o mesmo arquivo, só que para escrita. Continuamos com o perigo da manipulação sem locking, mas eliminamos a necessidade do arquivo temporário. Particularmente, continuo preferindo a solução 4, pelos mesmos motivos de antes. Uma nota sobre desempenho: quando o único fator a ser considerado é desempenho, a melhor solução é escrever em Assembly. Mais ainda: quando o único fator a ser considerado for desempenho, ou você está desenvolvendo algo muito específico *mesmo* ou, em geral, há uma chance muito grande de algo estar fundamentalmente errado no seu raciocínio. Esse erro é conhecido como "otimização prematura". Nas palavras de Donald Knuth: "Programadores desperdiçam um tempo enorme pensando sobre, ou se preocupando com, a velocidade de partes não críticas de seus programas, e essas tentativas de melhorar a eficiência na verdade acabam tendo um forte impacto negativo quando depuração e manutenção são consideradas. Precisamos esquecer eficiências menores em, digamos, 97% do tempo: otimização prematura é a raiz de todo o mal. No entanto não podemos deixar passar a oportunidade naqueles 3% crítico." Sempre que pensar em desempenho, lembre-se dessas sábias palavras. (Para saber mais sobre a questão: http://c2.com/cgi/wiki?PrematureOptimization) Para o seu caso, isso significa: programe SEMPRE com foco em legibilidade, testabilidade e manutenção. Preocupe-se com desempenho SOMENTE depois que isso se tornar um problema. Tem pessoas que se prendem a benchmarks do tipo: a função X me deixa fazer 32000 operações por segundo, enquanto que a função Y me deixa fazer em 27000 operações por segundo, então é FATO que devemos escolher a função X, pois é mais rápida, certo? Errado. Isso não deveria ser critério de desempate, vc deveria escolher a função que for mais clara e fácil de testar e de dar manutenção depois (extender, reduzir, alterar, acoplar, etc). Afinal, se você faz mais de 1000 operações por segundo com essa função, já está usando bastante. Mas repare que, mesmo que você faça 25000 operações *por segundo*, ambas as funções vão continuar com desempenho imperceptivelmente parecido. Isso é um caso típico de otimização prematura - você provavelmente não deveria nem estar procurando saber qual é a mais rápida nesse ponto. Pense novamente no seu caso: o programa nem está pronto ainda. Digamos que leve 3 segundos para rodar. E se levasse apenas 1 segundo (200% de melhoria em desempenho!!) faria alguma diferença real? E se levasse 5, em vez de 3? Há o caso maior também: se o seu programa leva 6 horas pra rodar, faz diferença levar 6 horas e 20 minutos? ou 5 horas e 40 minutos? Provavelmente não. Agora, se leva 6 horas e uma otimização o faria rodar em apenas 35 minutos, já é algo a se pensar. Acredite: as pessoas normalmente passam muito mais tempo dando manutenção a programas do que gastaram escrevendo os programas em primeiro lugar. Se vc usar um voodoo ninja sagaz só pra satisfazer sua sede de desempenho, vc está cometendo dois erros graves: o primeiro é que está perdendo tempo se preocupando com desempenho antes de isso ser um problema; e o segundo é que, dali pra frente, vc provavelmente vai gastar muito mais tempo tentando entender o que aquilo faz, como funciona e como resolver o pepino sem quebrar nada, do que tempo de fato resolvendo o problema. Em outras palavras, vc agilizou o tempo de execução mas retardou o tempo de manutenção. O problema é que 'execução' quem faz é a máquina, mas 'manutenção' quem faz é você. Apenas quando o tempo de execução *realmente* se tornar um problema é que, aí sim, vc pode procurar por gargalos. Note que não é saír otimizando loucamente onde der, e sim observar o comportamento da aplicação e ver onde ela *de fato* está gastando tempo. Muitas vezes não é onde você acha. Hoje, no mundo Perl, a melhor maneira de se identificar gargalos de desempenho é com o Devel::NYTProf (https://metacpan.org/module/Devel::NYTProf), que te dá um diagnóstico linha-a-linha de desempenho do seu programa. Usar é mole: perl -d:NYTProf meu_programa.pl # atenção: isso vai rodar o programa!! nytprofhtml --open e o seu navegador deve abrir automaticamente com os resultados! Você pode experimentar as diferentes soluções apresentadas nessa thread, ou só as 4, 4.5 e 5, mas sinceramente eu perderia meu tempo com coisas muito mais importantes como a resolução do problema em si ou novos desafios. A menos que o desempenho desse programa realmente esteja prejudicando o trabalho de alguém, caso em que eu rodaria o nytprof pra saber se o problema está realmente no arquivo temporário ou em outro lugar. Até que isso se torne um problema, como disse antes na resposta brevíssima: não importa :) []s -b _______________________________________________ Rio-pm mailing list Rio-pm@pm.org http://mail.pm.org/mailman/listinfo/rio-pm