En betydande besparing kan göras genom att undvika att slurpa in hela din indatafil i minnet som en list
rader.
Specifikt är dessa rader hemska för minnesanvändning, eftersom de involverar en maximal minnesanvändning på bytes
objekt storleken på hela filen, plus en list
rader med hela innehållet i filen också:
file_content = obj['Body'].read().decode('utf-8').splitlines(True)
for line in file_content:
För en 1 GB ASCII-textfil med 5 miljoner rader, på 64-bitars Python 3.3+, är det ett maximalt minneskrav på ungefär 2,3 GB för bara bytes
objekt, list
, och den individuella str
s i list
. Ett program som behöver 2,3 gånger så mycket RAM-minne som storleken på de filer det bearbetar kommer inte att skalas till stora filer.
För att fixa, ändra den ursprungliga koden till:
file_content = io.TextIOWrapper(obj['Body'], encoding='utf-8')
for line in file_content:
Med tanke på att obj['Body']
verkar vara användbar för lat streaming
detta bör ta bort båda kopior av hela fildata från minnet. Använda TextIOWrapper
betyder obj['Body']
läses lätt och avkodas i bitar (av några kB åt gången), och raderna upprepas också lätt; detta minskar minnesbehovet till en liten, i stort sett fast mängd (den maximala minneskostnaden beror på längden på den längsta raden), oavsett filstorlek.
Uppdatering:
Det ser ut som StreamingBody
implementerar inte io.BufferedIOBase
ABC. Den har sin egen dokumenterade API
men det kan användas för liknande ändamål. Om du inte kan skapa TextIOWrapper
gör jobbet åt dig (det är mycket effektivare och enklare om det kan fås att fungera), ett alternativ skulle vara att göra:
file_content = (line.decode('utf-8') for line in obj['Body'].iter_lines())
for line in file_content:
Till skillnad från att använda TextIOWrapper
, det gynnas inte av bulkavkodning av block (varje rad avkodas individuellt), men annars bör den fortfarande uppnå samma fördelar i form av minskad minnesanvändning.