txt - leer el contenido de un archivo en python
Python: la forma más rápida de procesar archivos grandes (1)
Tengo varios archivos delimitados por tabuladores de 3GB. Hay 20 millones de filas en cada archivo. Todas las filas deben procesarse de forma independiente, sin relación entre las dos filas. Mi pregunta es, ¿qué será más rápido? A. Leyendo línea por línea usando
with open() as infile:
for line in infile:
O bien B. ¿Leyendo el archivo en memoria en trozos y procesándolo, digamos 250 MB a la vez?
El procesamiento no es muy complicado, solo estoy tomando el valor de la columna1 a la Lista1, la columna2 a la Lista2, etc. Es posible que deba agregar algunos valores de columna juntos.
Estoy usando python 2.7 en una caja de linux que tiene 30GB de memoria. Texto ASCII.
¿Alguna forma de acelerar las cosas en paralelo? En este momento estoy usando el método anterior y el proceso es muy lento. ¿El uso de algún módulo CSVReader va a ayudar? No tengo que hacerlo en python, cualquier otro idioma o ideas de uso de base de datos son bienvenidos. Gracias.
Parece que su código está enlazado a E / S. Esto significa que el multiprocesamiento no va a ayudar, si pasa el 90% de su tiempo leyendo del disco, tener 7 procesos adicionales esperando en la próxima lectura no ayudará en nada.
Y, aunque el uso de un módulo de lectura CSV (ya sea el csv
de stdlib o algo como NumPy o Pandas) puede ser una buena idea para la simplicidad, es poco probable que haya una gran diferencia en el rendimiento.
Sin embargo, vale la pena comprobar que realmente estás vinculado a E / S, en lugar de simplemente adivinar. Ejecute su programa y vea si su uso de CPU es cercano al 0% o cercano al 100% o un núcleo. Haga lo que Amadan sugirió en un comentario, ejecute el programa con solo pass
para el procesamiento y vea si eso se corta el 5% del tiempo o el 70%. Incluso puede intentar comparar con un bucle sobre os.open
y os.read(1024*1024)
o algo así y ver si eso es más rápido.
Desde que usas Python 2.x, Python confía en la biblioteca C stdio para adivinar cuánto almacenar en búfer a la vez, por lo que podría valer la pena forzarlo a almacenar más. La forma más sencilla de hacerlo es usar readlines(bufsize)
para algunos bufsize
grandes. (Puede probar diferentes números y medirlos para ver dónde está el pico. En mi experiencia, generalmente, entre 64K-8MB es aproximadamente el mismo, pero dependiendo de su sistema puede ser diferente, especialmente si está leyendo, por ejemplo, fuera de un sistema de archivos de red con un gran rendimiento pero una latencia horrible que empapa el rendimiento frente a la latencia de la unidad física real y el almacenamiento en caché que hace el sistema operativo).
Así por ejemplo:
bufsize = 65536
with open(path) as infile:
while True:
lines = infile.readlines(bufsize)
if not lines:
break
for line in lines:
process(line)
Mientras tanto, asumiendo que está en un sistema de 64 bits, puede intentar usar mmap
lugar de leer el archivo en primer lugar. Esto ciertamente no está garantizado para ser mejor, pero puede ser mejor, dependiendo de su sistema. Por ejemplo:
with open(path) as infile:
m = mmap.mmap(infile, 0, access=mmap.ACCESS_READ)
Un mmap
Python es una especie de objeto extraño: actúa como una str
y como un file
al mismo tiempo, por lo que puede, por ejemplo, iterar manualmente la búsqueda de nuevas líneas, o puede llamar a readline
en él como si fuera un archivo. Ambos tomarán más procesamiento de Python que iterar el archivo como líneas o hacer líneas de lectura por lotes (porque un bucle que estaría en C ahora está en Python puro ... aunque tal vez puedas solucionarlo con re
, o con una simple extensión de Cython ?) ... pero la ventaja de E / S de que el sistema operativo sepa lo que está haciendo con la asignación puede inundar la desventaja de la CPU.
Desafortunadamente, Python no expone la llamada madvise
que usaría para modificar las cosas en un intento de optimizar esto en C (por ejemplo, configurando explícitamente MADV_SEQUENTIAL
lugar de hacer la MADV_SEQUENTIAL
del kernel, o forzando páginas enormes y transparentes), pero en realidad puede ctypes
la función de libc
.