sql >> Base de Datos >  >> RDS >> PostgreSQL

Error de memoria al utilizar el método read() para leer un archivo JSON de gran tamaño desde Amazon S3

Se pueden obtener ahorros significativos al evitar sorber todo el archivo de entrada en la memoria como una list de líneas.

Específicamente, estas líneas son terribles en el uso de memoria, ya que implican un uso máximo de memoria de bytes objeto el tamaño de todo el archivo, más una list de líneas con el contenido completo del archivo también:

file_content = obj['Body'].read().decode('utf-8').splitlines(True)
for line in file_content:

Para un archivo de texto ASCII de 1 GB con 5 millones de líneas, en Python 3.3+ de 64 bits, el requisito de memoria máxima es de aproximadamente 2,3 GB para solo los bytes objeto, la list , y el str individual s en la list . Un programa que necesita 2,3 veces más RAM que el tamaño de los archivos que procesa no escalará a archivos grandes.

Para solucionarlo, cambie ese código original a:

file_content = io.TextIOWrapper(obj['Body'], encoding='utf-8')
for line in file_content:

Dado que obj['Body'] parece ser utilizable para transmisión perezosa esto debería eliminar ambos copias de los datos completos del archivo de la memoria. Usando TextIOWrapper significa obj['Body'] se lee con pereza y se decodifica en fragmentos (de unos pocos KB a la vez), y las líneas también se iteran con pereza; esto reduce las demandas de memoria a una cantidad pequeña y en gran medida fija (el costo máximo de la memoria dependería de la longitud de la línea más larga), independientemente del tamaño del archivo.

Actualización:

Se parece a StreamingBody no implementa io.BufferedIOBase A B C. Tiene su propia API documentada sin embargo, eso puede usarse para un propósito similar. Si no puedes hacer el TextIOWrapper haga el trabajo por usted (es mucho más eficiente y simple si se puede hacer que funcione), una alternativa sería hacer:

file_content = (line.decode('utf-8') for line in obj['Body'].iter_lines())
for line in file_content:

A diferencia de usar TextIOWrapper , no se beneficia de la decodificación masiva de bloques (cada línea se decodifica individualmente), pero por lo demás debería lograr los mismos beneficios en términos de uso de memoria reducido.