Por que o mmap do Python não funciona com arquivos grandes?
[Edit: este problema se aplica apenas a sistemas de 32 bits. Se o seu computador, seu sistema operacional e sua implementação em Python forem de 64 bits, os arquivos enormes do mmap-ing funcionarão de forma confiável e serão extremamente eficientes.]
Eu estou escrevendo um módulo que, entre outras coisas, permite acesso de leitura bit a bit aos arquivos. Os arquivos podem ser grandes (centenas de GB), então eu escrevi uma classe simples que me permite tratar o arquivo como uma string e esconde toda a busca e leitura.
Na época em que escrevi minha turma de invólucros eu não sabia sobre omódulo mmap. Ao ler a documentação do mmap eu pensei"ótimo - isso é exatamente o que eu precisava, vou pegar meu código e substituí-lo por um mmap. É provavelmente muito mais eficiente e é sempre bom excluir código."
O problema é que o mmap não funciona para arquivos grandes! Isso é muito surpreendente para mim, como eu pensei que talvez fosse a aplicação mais óbvia. Se o arquivo estiver acima de alguns gigabytes, recebo umEnvironmentError: [Errno 12] Cannot allocate memory
. Isso só acontece com uma compilação Python de 32 bits, então parece que está ficando sem espaço de endereço, mas não consigo encontrar nenhuma documentação sobre isso.
Meu código é apenas
f = open('somelargefile', 'rb')
map = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ)
Então minha pergunta éestou faltando alguma coisa óbvia aqui? Existe uma maneira de obter o mmap para trabalhar portavelmente em arquivos grandes ou devo voltar para o meu wrapper de arquivo ingênuo?
Atualização: Parece haver uma sensação de que o mmap do Python deve ter as mesmas restrições que o mmap POSIX. Para expressar melhor minha frustração aqui está uma classe simples que tem uma pequena parte da funcionalidade do mmap.
import os
class Mmap(object):
def __init__(self, f):
"""Initialise with a file object."""
self.source = f
def __getitem__(self, key):
try:
# A slice
self.source.seek(key.start, os.SEEK_SET)
return self.source.read(key.stop - key.start)
except AttributeError:
# single element
self.source.seek(key, os.SEEK_SET)
return self.source.read(1)
É somente leitura e não faz nada extravagante, mas eu posso fazer isso da mesma forma que com um mmap:
map2 = Mmap(f)
print map2[0:10]
print map2[10000000000:10000000010]
exceto que não há restrições no tamanho do arquivo. Não é muito difícil realmente ...