mmap — Archivos de mapas de memoria¶
Propósito: | Mapas de memoria en lugar de leer los contenidos directamente. |
---|
El mapeo de memoria de un archivo usa el sistema de memoria virtual del sistema operativo para acceder a los datos en el sistema de archivos directamente, en lugar de utilizar funciones normales de E/S. El mapeo de memoria típicamente mejora el rendimiento de E/S porque no implica una llamada al sistema por separado para cada acceso y no requiere copiar datos entre búfers – la memoria se accede directamente tanto por el núcleo como por la aplicación de usuario.
Los archivos mapeados en la memoria se pueden tratar como cadenas mutables o
como objetos de archivos, según la necesidad. Un archivo mapeado soporta los
métodos esperados de la interfaz de archivo, como close()
, flush()
,
read()
, readline()
, seek()
, tell()
, y write()
. También
soporta la interfaz de cadenas de texto, con características tales como rebanar
y métodos como find()
.
Todos los ejemplos utilizan el archivo de texto lorem.txt
, que contiene un
pedazo de lorem ipsum. Para referencia, el texto del archivo es
Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
Donec egestas, enim et consectetuer ullamcorper, lectus ligula rutrum leo,
a elementum elit tortor eu quam. Duis tincidunt nisi ut ante. Nulla
facilisi. Sed tristique eros eu libero. Pellentesque vel
arcu. Vivamus purus orci, iaculis ac, suscipit sit amet, pulvinar eu,
lacus. Praesent placerat tortor sed nisl. Nunc blandit diam egestas
dui. Pellentesque habitant morbi tristique senectus et netus et
malesuada fames ac turpis egestas. Aliquam viverra fringilla
leo. Nulla feugiat augue eleifend nulla. Vivamus mauris. Vivamus sed
mauris in nibh placerat egestas. Suspendisse potenti. Mauris
massa. Ut eget velit auctor tortor blandit sollicitudin. Suspendisse
imperdiet justo.
Nota
Hay diferencias en los argumentos y comportamientos para mmap()
entre
Unix y Windows, que no se discuten por completo aquí. Para más detalles,
consulta la documentación de la biblioteca estándar.
Leer¶
Usa la función mmap()
para crear un archivo mapeado en memoria. El primer
argumento es un descriptor de archivo, ya sea del método fileno()
de un
objeto file
o de os.open()
. El llamador es responsable de abrir el
archivo antes de invocar mmap()
, y cerrarlo después de que ya no es
necesario.
El segundo argumento de mmap()
es un tamaño en bytes para la porción del
archivo a mapear. Si el valor es 0
, el archivo completo es mapeado. Si el
tamaño es mayor que el tamaño actual del archivo, el archivo es extendido.
Nota
Windows no admite la creación de un mapeo de longitud cero.
Un argumento opcional de palabra clave, access
, es soportado por ambas
plataformas. Usa ACCESS_READ
para acceso de solo lectura,``
ACCESS_WRITE
para escritura directa (las asignaciones a la memoria van
directamente al archivo), o ACCESS_COPY
para copiar al escribir (las
asignaciones a la memoria no se escriben en el archivo).
import mmap
with open('lorem.txt', 'r') as f:
with mmap.mmap(f.fileno(), 0,
access=mmap.ACCESS_READ) as m:
print('First 10 bytes via read :', m.read(10))
print('First 10 bytes via slice:', m[:10])
print('2nd 10 bytes via read :', m.read(10))
El puntero del archivo rastrea el último byte al que se accede a través de una
operación de segmentación. En este ejemplo, el puntero avanza 10 bytes después
de la primera lectura. Luego se restablece al principio del archivo por la
operación de segmentación, y se mueve hacia adelante 10 bytes de nuevo por la
segmentación. Después de la operación de segmentación, llamando a read()
nuevamente da los bytes 11-20 en el archivo.
$ python3 mmap_read.py
First 10 bytes via read : b'Lorem ipsu'
First 10 bytes via slice: b'Lorem ipsu'
2nd 10 bytes via read : b'm dolor si'
Escribir¶
Para configurar el archivo mapeado en memoria para recibir actualizaciones,
comience abriéndolo para adjuntar con el modo 'r+'
(no 'w'
) antes de
mapearlo. Luego usa cualquiera de los métodos de la interfaz que cambian los
datos (write()
, asignación a un segmento, etc.).
El siguiente ejemplo utiliza el modo de acceso predeterminado de
ACCESS_WRITE
y asignando a un segmento para modificar parte de una línea en
su lugar.
import mmap
import shutil
# Copy the example file
shutil.copyfile('lorem.txt', 'lorem_copy.txt')
word = b'consectetuer'
reversed = word[::-1]
print('Looking for :', word)
print('Replacing with :', reversed)
with open('lorem_copy.txt', 'r+') as f:
with mmap.mmap(f.fileno(), 0) as m:
print('Before:\n{}'.format(m.readline().rstrip()))
m.seek(0) # rewind
loc = m.find(word)
m[loc:loc + len(word)] = reversed
m.flush()
m.seek(0) # rewind
print('After :\n{}'.format(m.readline().rstrip()))
f.seek(0) # rewind
print('File :\n{}'.format(f.readline().rstrip()))
La palabra «consectetuer
» se reemplaza en medio de la primera línea en
memoria y en el archivo.
$ python3 mmap_write_slice.py
Looking for : b'consectetuer'
Replacing with : b'reutetcesnoc'
Before:
b'Lorem ipsum dolor sit amet, consectetuer adipiscing elit.'
After :
b'Lorem ipsum dolor sit amet, reutetcesnoc adipiscing elit.'
File :
Lorem ipsum dolor sit amet, reutetcesnoc adipiscing elit.
Modo de Copia¶
Usando la configuración de acceso ACCESS_COPY
no escribe cambios al archivo
en disco.
import mmap
import shutil
# Copy the example file
shutil.copyfile('lorem.txt', 'lorem_copy.txt')
word = b'consectetuer'
reversed = word[::-1]
with open('lorem_copy.txt', 'r+') as f:
with mmap.mmap(f.fileno(), 0,
access=mmap.ACCESS_COPY) as m:
print('Memory Before:\n{}'.format(
m.readline().rstrip()))
print('File Before :\n{}\n'.format(
f.readline().rstrip()))
m.seek(0) # rewind
loc = m.find(word)
m[loc:loc + len(word)] = reversed
m.seek(0) # rewind
print('Memory After :\n{}'.format(
m.readline().rstrip()))
f.seek(0)
print('File After :\n{}'.format(
f.readline().rstrip()))
Es necesario rebobinar el identificador de archivo en este ejemplo por separado
desde el identificador mmap
, porque el estado interno de los dos objetos se
mantienen por separado.
$ python3 mmap_write_copy.py
Memory Before:
b'Lorem ipsum dolor sit amet, consectetuer adipiscing elit.'
File Before :
Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
Memory After :
b'Lorem ipsum dolor sit amet, reutetcesnoc adipiscing elit.'
File After :
Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
Expresiones Regulares¶
Como un archivo mapeado en memoria puede actuar como una cadena, puede usarse
con otros módulos que operan en cadenas, tales como expresiones regulares.
Este ejemplo encuentra todas las oraciones con «nulla
» en ellas.
import mmap
import re
pattern = re.compile(rb'(\.\W+)?([^.]?nulla[^.]*?\.)',
re.DOTALL | re.IGNORECASE | re.MULTILINE)
with open('lorem.txt', 'r') as f:
with mmap.mmap(f.fileno(), 0,
access=mmap.ACCESS_READ) as m:
for match in pattern.findall(m):
print(match[1].replace(b'\n', b' '))
Debido a que el patrón incluye dos grupos, el valor de retorno de findall()
es una secuencia de tuplas. La declaración print
saca la oración
correspondiente y reemplaza las líneas nuevas con espacios para que cada
resultado se imprima en una sola línea.
$ python3 mmap_regex.py
b'Nulla facilisi.'
b'Nulla feugiat augue eleifend nulla.'
Ver también
- Documentación de la biblioteca estándar para mmap
- Notas para portar Python 2 a 3 para mmap
os
– El móduloos
.re
– Expresiones Regulares.