Iteratori e generatori : come elaborare dati consumando meno memoria

Iteratori e generatori : come elaborare dati consumando meno memoria
3 min di lettura

Uno script incaricato di riassumere il registro dei pagamenti ha funzionato senza incidenti per un anno, prima di fallire su un file troppo voluminoso. Un tutorial dedicato agli iteratori e ai generatori di Python mostra come costruire catene di elaborazione che leggono i dati un record alla volta, senza caricarli tutti in memoria.

  • Lo script è fallito su un file da 9 GB perché caricava tutti i record in una lista.
  • Iteratori e generatori leggono i dati un record alla volta, riducendo il consumo di memoria.
  • Funzioni come list() e sorted() riportano l’intero flusso in memoria.
  • Su 200 000 righe, tracemalloc misura 198 MB di picco con la lista e 0,4 MB con il flusso.

Nel caso descritto, lo script apriva il file, costruiva una lista di record analizzati, filtrava gli errori, poi visualizzava una tabella. Dopo un cambio nella rotazione dei registri, una settimana di traffico è finita in un unico file da 9 GB. L’elaborazione notturna si è interrotta con un MemoryError prima di aver prodotto il minimo riassunto. Secondo l’autore, la logica di analisi non era in causa: il problema veniva dalla lista, che obbliga a conservare tutti i record contemporaneamente.

Il funzionamento si basa su un contratto semplice. Un iterabile, come una lista, una stringa di caratteri o un file aperto, può fornire un iteratore, cioè un cursore che avanza elemento per elemento e non torna mai indietro. Il ciclo for chiama questi passaggi automaticamente, e la fine della sequenza si segnala con l’eccezione StopIteration, che non è un errore. Un iteratore esaurito non si reinizializza: una funzione che restituisce « nulla » durante una seconda lettura non è necessariamente vuota, è semplicemente già stata consumata.

Il tutorial raccomanda di iniziare dall’oggetto file, che è già un iteratore. Leggere un file con f.readlines() crea una lista di tutte le righe, mentre for line in f legge solo un blocco bufferizzato alla volta. Le funzioni generatrici, che usano la parola chiave yield, permettono poi di suddividere l’analisi in fasi denominate. L’istruzione yield from concatena più file di rotazione come un unico flusso, e le espressioni generatrici, scritte tra parentesi, servono per piccole trasformazioni intermedie. L’autore segnala una trappola: la parte più a sinistra di un’espressione generatrice viene valutata immediatamente.

Misurare prima di fidarsi

Il tutorial insiste anche sui punti in cui la lista ritorna discretamente. Le chiamate list(), sorted(), un dizionario che raggruppa i record per identificativo di richiesta, o la costruzione di un DataFrame reintroducono l’intero flusso in memoria. I generatori non sono nemmeno più veloci delle liste: il loro interesse è una memoria limitata e fasi riorganizzabili. Per le elaborazioni in batch, Python 3.12 propone itertools.batched(), e una ricetta equivalente su islice è fornita per le versioni precedenti.

Per verificare il comportamento reale, l’autore raccomanda il modulo tracemalloc, che misura la memoria allocata da Python, in valore corrente e in picco. Su un registro sintetico di 200 000 righe, di circa 17 MB, la versione « lista » raggiunge un picco di 198 MB su un computer portatile, contro 0,4 MB per la versione in flusso. L’autore precisa che si tratta dei risultati di una singola esecuzione, e non di un benchmark. Ricorda inoltre che tracemalloc non vede le allocazioni delle estensioni in C né la cache del sistema.

I limiti del flusso

Alcune elaborazioni non possono essere condotte in flusso. Un ordinamento globale, una deduplicazione esatta sull’intero file o un percentile calcolato su tutti i valori di latenza richiedono di conoscere tutti i record. In questo caso, il tutorial evoca un algoritmo approssimativo basato su un campione, o uno strumento esterno che ordina su disco.

Il tutorial precisa infine che questo approccio rimane in Python puro. Pandas, Spark, Dask o i flussi asincroni rispondono a problemi simili, ma non sono necessari per un file di registro, un’esportazione o uno scarico di dati che sta sul disco senza stare nella memoria RAM.

S’abonner
Notification pour
guest

0 Commentaires
Le plus ancien
Le plus récent Le plus populaire
0
Nous aimerions avoir votre avis, veuillez laisser un commentaire.x