Ho avuto un problema simile nella lettura di un grafico da un file. L'elaborazione ha incluso il calcolo di una matrice float 200 000x200 000 (una riga alla volta) che non si adattava alla memoria. Cercando di liberare la memoria tra i calcoli usando gc.collect()
risolto l'aspetto relativo alla memoria del problema ma si sono verificati problemi di prestazioni: non so perché ma anche se la quantità di memoria utilizzata è rimasta costante, ogni nuova chiamata a ha richiesto un po 'di più tempo rispetto al precedente. Quindi abbastanza rapidamente la raccolta dei rifiuti ha richiesto la maggior parte del tempo di calcolo.
Per risolvere entrambi i problemi di memoria e prestazioni, sono passato all'uso di un trucco multithreading che ho letto da qualche parte (mi dispiace, non riesco più a trovare il post correlato). Prima di leggere ogni riga del file in un grande ciclo for
, elaborarlo ed eseguire gc.collect()
una volta ogni tanto per liberare spazio nella memoria. Ora chiamo una funzione che legge ed elabora un blocco del file in una nuova discussione. Una volta terminato il thread, la memoria viene automaticamente liberata senza lo strano problema di prestazioni.
In pratica funziona così:
from dask import delayed // this module wraps the multithreading
def f(storage, index, chunk_size): // the processing function
// read the chunk of size chunk_size starting at index in the file
// process it using data in storage if needed
// append data needed for further computations to storage
return storage
partial_result = delayed([]) // put into the delayed() the constructor for your data structure
// i personally use "delayed(nx.Graph())" since I am creating a networkx Graph
chunk_size = 100 // ideally you want this as big as possible while still enabling the computations to fit in memory
for index in range(0, len(file), chunk_size):
// we indicates to dask that we will want to apply f to the parameters partial_result, index, chunk_size
partial_result = delayed(f)(partial_result, index, chunk_size)
// no computations are done yet !
// dask will spawn a thread to run f(partial_result, index, chunk_size) once we call partial_result.compute()
// passing the previous "partial_result" variable in the parameters assures a chunk will only be processed after the previous one is done
// it also allows you to use the results of the processing of the previous chunks in the file if needed
// this launches all the computations
result = partial_result.compute()
// one thread is spawned for each "delayed" one at a time to compute its result
// dask then closes the tread, which solves the memory freeing issue
// the strange performance issue with gc.collect() is also avoided
Perché non stampare i triangoli ad un file intermedio, e leggere di nuovo di nuovo quando ne hai bisogno? –