Znaczne oszczędności można uzyskać, unikając pożerania całego pliku wejściowego w pamięci jako list linii.
W szczególności te wiersze są straszne pod względem wykorzystania pamięci, ponieważ obejmują szczytowe użycie pamięci bytes określ rozmiar całego pliku plus list wierszy z pełną zawartością pliku:
file_content = obj['Body'].read().decode('utf-8').splitlines(True)
for line in file_content:
Dla pliku tekstowego ASCII o pojemności 1 GB z 5 milionami wierszy, w 64-bitowym Pythonie 3.3+, szczytowe zapotrzebowanie na pamięć wynosi około 2,3 GB dla tylko bytes obiekt, list i indywidualny str s na list . Program, który potrzebuje 2,3 razy więcej pamięci RAM niż rozmiar przetwarzanych plików, nie będzie skalowany do dużych plików.
Aby naprawić, zmień oryginalny kod na:
file_content = io.TextIOWrapper(obj['Body'], encoding='utf-8')
for line in file_content:
Biorąc pod uwagę, że obj['Body'] wydaje się, że nadaje się do leniwego przesyłania strumieniowego
to powinno usunąć oba kopie pełnych danych pliku z pamięci. Korzystanie z TextIOWrapper oznacza obj['Body'] jest leniwie odczytywany i dekodowany w kawałkach (po kilka KB na raz), a wiersze są również leniwie iterowane; zmniejsza to zapotrzebowanie na pamięć do małej, w dużej mierze stałej wartości (szczytowy koszt pamięci zależy od długości najdłuższej linii), niezależnie od rozmiaru pliku.
Aktualizacja:
Wygląda jak StreamingBody nie implementuje io.BufferedIOBase ABC. Ma własny udokumentowany interfejs API
jednak można to wykorzystać w podobnym celu. Jeśli nie możesz utworzyć TextIOWrapper wykonać pracę za Ciebie (jest to o wiele bardziej wydajne i prostsze, jeśli można sprawić, aby działał), alternatywą byłoby:
file_content = (line.decode('utf-8') for line in obj['Body'].iter_lines())
for line in file_content:
W przeciwieństwie do używania TextIOWrapper , nie korzysta z masowego dekodowania bloków (każda linia jest dekodowana indywidualnie), ale poza tym powinna nadal osiągać te same korzyści pod względem zmniejszonego zużycia pamięci.