writelines write print one multiple funcion create python performance file file-writing

print - Python writelines() y write() enorme diferencia horaria



save list python (3)

Como complemento a la respuesta de Martijn, la mejor manera sería evitar construir la lista utilizando join en primer lugar.

Simplemente pase la comprensión de un generador a las writelines de writelines , agregando la nueva línea al final: sin asignación de memoria innecesaria y sin bucle (además de la comprensión)

myWrite.writelines("{}/n".format(x) for x in my_list)

Estaba trabajando en una secuencia de comandos que lee una carpeta de archivos (cada uno de un tamaño que va desde 20 MB a 100 MB), modifica algunos datos en cada línea y escribe en una copia del archivo.

with open(inputPath, ''r+'') as myRead: my_list = myRead.readlines() new_my_list = clean_data(my_list) with open(outPath, ''w+'') as myWrite: tempT = time.time() myWrite.writelines(''/n''.join(new_my_list) + ''/n'') print(time.time() - tempT) print(inputPath, ''Cleaning Complete.'')

Al ejecutar este código con un archivo de 90 MB (~ 900,000 líneas), se imprimió 140 segundos como el tiempo necesario para escribir en el archivo. Aquí utilicé writelines() . Así que busqué diferentes formas de mejorar la velocidad de escritura de los archivos, y en la mayoría de los artículos que leí, decían que write() y writelines() no deberían mostrar ninguna diferencia ya que estoy escribiendo una única cadena concatenada. También verifiqué el tiempo necesario para solo lo siguiente en la declaración:

new_string = ''/n''.join(new_my_list) + ''/n''

Y solo tomó 0.4 segundos, por lo que el gran tiempo no fue debido a la creación de la lista. Solo para probar write() Probé este código:

with open(inputPath, ''r+'') as myRead: my_list = myRead.readlines() new_my_list = clean_data(my_list) with open(outPath, ''w+'') as myWrite: tempT = time.time() myWrite.write(''/n''.join(new_my_list) + ''/n'') print(time.time() - tempT) print(inputPath, ''Cleaning Complete.'')

Y se imprimió 2,5 segundos. ¿Por qué hay una diferencia tan grande en el tiempo de escritura del archivo para write() y writelines() a pesar de que son los mismos datos? ¿Es este comportamiento normal o hay algo mal en mi código? El archivo de salida parece ser el mismo para ambos casos, por lo que sé que no hay pérdida de datos.


El método ''write (arg)'' espera que la cadena sea su argumento. Así que una vez que llama, escribirá directamente. Esta es la razón por la que es mucho más rápido. donde como si estuviera utilizando el método writelines() , espera una lista de cadenas como iterador. por lo tanto, incluso si está enviando datos a writelines de writelines , asume que tiene iterador e intenta iterar sobre él. por lo tanto, como es un iterador, tomará algún tiempo para iterarlo y escribirlo.

Está claro ?


file.writelines() espera un iterable de cadenas. Luego procede a hacer un bucle y llamar a file.write() para cada cadena en el iterable. En Python, el método hace esto:

def writelines(self, lines) for line in lines: self.write(line)

Usted está pasando en una sola cadena grande, y una cadena es también una iterable de cadenas. Al iterar, obtiene caracteres individuales , cadenas de longitud 1. Así que, en efecto, está haciendo llamadas separadas a len(data) a file.write() . Y eso es lento, porque está creando un búfer de escritura de un solo carácter a la vez.

No pase una sola cadena a file.writelines() . Pase en una lista o tupla u otro iterable en su lugar.

Puede enviar líneas individuales con nueva línea agregada en una expresión de generador, por ejemplo:

myWrite.writelines(line + ''/n'' for line in new_my_list)

Ahora, si pudiera convertir clean_data() un generador , generando líneas limpias, podría transmitir datos desde el archivo de entrada, a través de su generador de limpieza de datos, y enviarlo al archivo de salida sin utilizar más memoria de la necesaria para la lectura y escritura. buffers y sin embargo se necesita mucho estado para limpiar sus líneas:

with open(inputPath, ''r+'') as myRead, open(outPath, ''w+'') as myWrite: myWrite.writelines(line + ''/n'' for line in clean_data(myRead))

Además, consideraría actualizar clean_data() para emitir líneas con nuevas líneas incluidas.