Marcelo Toledo escreveu um artigo comparando a sua implmentação em C de um corretor ortográfico poposto por Peter Norgiv com a versão original em Python.
Porém Marcelo Toledo ao realizar essa comparação não levou em consideração que o exemplo desenvolvido por Peter Norvig era apensa um protótipo. Sendo assim, ele resolveu comparar ambos os programas, em C e Python, utilizando arquivos cada vez maiores e ilustrando a diferença de performance entre eles.
No código de Peter Norvig ele lê o arquivo de uma vez. Dá para imaginar o que acontenceu, baixa performance e "crash" com arquivos maiores de 100M devido a falta de RAM. :-(
Essa é a linha na qual o programa de Peter Norvig lê o arquivo e processa ele:
Como eu fui questionado por um colega (Robson Peixoto) sobre o "porque" do problema com o código do corretor ortográfico. Resolvi então escrever um pequeno script que copia arquivos binários da forma correta. E assim fica claro que Python não tem problemas em manipular arquivos maiores que 100MB. ;-)
Segue um teste de uso do script copyfile.py
segundos para copiar um arquivo de 416MB, ou seja, 10MB/s aproximadamente.
Abaixo o código do script copyfile.py
Porém Marcelo Toledo ao realizar essa comparação não levou em consideração que o exemplo desenvolvido por Peter Norvig era apensa um protótipo. Sendo assim, ele resolveu comparar ambos os programas, em C e Python, utilizando arquivos cada vez maiores e ilustrando a diferença de performance entre eles.
No código de Peter Norvig ele lê o arquivo de uma vez. Dá para imaginar o que acontenceu, baixa performance e "crash" com arquivos maiores de 100M devido a falta de RAM. :-(
Essa é a linha na qual o programa de Peter Norvig lê o arquivo e processa ele:
NWORDS = train(words(file('big.txt').read()))
Infelizmente Marcelo Toledo não procurou saber qual era o "bug" do código, deixando no ar uma idéia de que C é robusto é Python é uma linguagem não confiável.Como eu fui questionado por um colega (Robson Peixoto) sobre o "porque" do problema com o código do corretor ortográfico. Resolvi então escrever um pequeno script que copia arquivos binários da forma correta. E assim fica claro que Python não tem problemas em manipular arquivos maiores que 100MB. ;-)
Segue um teste de uso do script copyfile.py
Ou seja, sem usar muita CPU e nem mesmo RAM, esse script demorou 40ruda@zion /tmp $ du -sh livecd-i686-installer-2007.0.iso
416M livecd-i686-installer-2007.0.iso
ruda@zion /tmp $ time ./copyfile.py livecd-i686-installer-2007.0.iso teste.iso
real 0m39.708s
user 0m4.517s
sys 0m3.747s
segundos para copiar um arquivo de 416MB, ou seja, 10MB/s aproximadamente.
Abaixo o código do script copyfile.py
#!/bin/env python
# -*- coding: utf-8 -*-
import sys
try:
origem = sys.argv[1]
destino = sys.argv[2]
except IndexError:
print "Modo de usar: copyfile.py origem destino"
sys.exit(1)
#Exemplo de leitura e gravação de arquivos grandes - usando modo binário
input = file(origem, 'rb')
output = file(destino, "wb")
for line in input:
output.write(line)
#Fechando os arquivos
input.close()
output.close()
Comentários
No caso de um arquivo binário (como o tal .iso), seria mais aconselhável usar file.read(tamanho) (http://docs.python.org/lib/bltin-file-objects.html#l2h-302), pois ler por linhas pode chegar ao extremo do arquivo inteiro ser considerado apenas uma (na falta de um \n).
Fora isso muito bom post, eu também odeio este tipo de difamação gratuita.
Você tem razão.
Nesse caso ficaria assim:
data = input.read(4192)
while data:
output.write(data)
data = input.read(4192)
Os tempos de execução foram bem parecidos, mas poderia não ser. ;-)
real 0m41.049s
user 0m0.403s
sys 0m1.317s
A minha dúvida, e para isso teria que ver o código em C do objeto file, é se ele não é "esperto" na iteração com arquivos binários..?
input = open(sys.argv[0], 'rb')
output = open(sys.argv[1], 'wb')
shutil.copyfileobj(input, output)
Valeu pela dica. ;-)
De qualquer forma eu queria mostrar um exemplo de como ler o arquivo em blocos ou em linhas e não ele de uma vez como fez o Peter Norvig.
Foi ai que surgiu a idéia do script para copiar um arquivo grande, provando que Python, desde que programado de forma correta, consegue trabalhar muito bem com arquvos grandes.
Eu não quiz corrigir o código do corretor, pois achei que seria mais complicado de fazer e de testar.
Inclusive por que ele processa tudo de uma vez e joga na RAM. Na verdade seria necessário criar uma estrutura de armazenamento do arquivo processado, com índices de busca para que ese corretor funcione com dicionários maiores. :-(
Usando file.read() e .seek() deixou o programa extremamente ineficaz. Solução: mmap (http://docs.python.org/lib/module-mmap.html).
Muito boa dica, eu nunca tinha ouvido falar no módulo "mmap". :-(
Nada como aprender coisas novas, ainda mais como os mestres. :-)