sql >> Database >  >> RDS >> PostgreSQL

MemoryError bij gebruik van de read()-methode bij het lezen van een groot JSON-bestand van Amazon S3

U kunt aanzienlijke besparingen behalen door te voorkomen dat u uw hele invoerbestand in het geheugen slurpt als een list lijnen.

In het bijzonder zijn deze regels verschrikkelijk wat betreft geheugengebruik, in die zin dat ze een piekgeheugengebruik van bytes met zich meebrengen object de grootte van uw hele bestand, plus een list van regels met ook de volledige inhoud van het bestand:

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

Voor een ASCII-tekstbestand van 1 GB met 5 miljoen regels, op 64 bit Python 3.3+, is dat een piekgeheugenvereiste van ongeveer 2,3 GB voor slechts de bytes object, de list , en de individuele str s in de list . Een programma dat 2,3x zoveel RAM nodig heeft als de grootte van de bestanden die het verwerkt, schaalt niet naar grote bestanden.

Om dit op te lossen, wijzigt u die originele code in:

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

Gezien het feit dat obj['Body'] lijkt bruikbaar voor luie streaming dit zou beide moeten verwijderen kopieën van de volledige bestandsgegevens uit het geheugen. TextIOWrapper gebruiken betekent obj['Body'] wordt lui gelezen en gedecodeerd in brokken (van een paar KB per keer), en de regels worden ook lui herhaald; dit vermindert de geheugenbehoefte tot een kleine, grotendeels vaste hoeveelheid (de piekgeheugenkosten zijn afhankelijk van de lengte van de langste regel), ongeacht de bestandsgrootte.

Bijwerken:

Het lijkt op StreamingBody implementeert de io.BufferedIOBase . niet ABC. Het heeft wel zijn eigen gedocumenteerde API dat kan echter voor een soortgelijk doel worden gebruikt. Als u de TextIOWrapper . niet kunt maken het werk voor u doen (het is veel efficiënter en eenvoudiger als het kan worden gemaakt), een alternatief zou zijn om te doen:

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

In tegenstelling tot het gebruik van TextIOWrapper , profiteert het niet van bulkdecodering van blokken (elke regel wordt afzonderlijk gedecodeerd), maar verder zou het nog steeds dezelfde voordelen moeten behalen in termen van verminderd geheugengebruik.




  1. Paginering met MySQL LIMIT, OFFSET

  2. Zoekfunctie met meerdere criteria - PHP/MySQL

  3. Mysql:waarden tussen twee kolommen selecteren

  4. Stroombestand absoluut pad Nifi