2015-05-18 19 views
14

Ho più file delimitati da tabulazione da 3 GB. Ci sono 20 milioni di righe in ogni file. Tutte le righe devono essere elaborate in modo indipendente, nessuna relazione tra due righe qualsiasi. La mia domanda è, quale sarà più veloce A. linea di lettura per riga usando `Python: il modo più veloce per elaborare file di grandi dimensioni

with open() as infile: 
      for line in infile: 

O B. Leggere il file nella memoria in blocchi e la trasformazione, dire 250 MB alla volta?

L'elaborazione non è molto complicata, sto semplicemente prendendo il valore in colonna1 in Lista1, colonna2 in Lista2 ecc. Potrebbe essere necessario aggiungere alcuni valori di colonna insieme.

Sto usando python 2.7 su un box Linux con 30 GB di memoria. Testo ASCII.

Un modo per velocizzare le cose in parallelo? In questo momento sto usando il metodo precedente e il processo è molto lento. Sta usando un modulo CSVReader per aiutare? Non ho bisogno di farlo in Python, qualsiasi altra lingua o idee di utilizzo del database sono benvenute. Grazie.

`

+0

multiprocessing; lettura iterativa chunked. A 3 GB per file, ** NON ** vuoi leggerlo interamente in memoria; puoi soffiare le tue risorse di memoria. –

+0

Sembra che un database ti aiuti a seconda del tipo di elaborazione che stai facendo. – squiguy

+0

Non se questa è un'attività a singolo lancio; dati-in; in lavorazione; uscita dati; cancella i dati di origine. –

risposta

23

Sembra che il tuo codice è di I/O bound. Ciò significa che il multiprocessing non ti aiuterà: se passi il 90% del tuo tempo a leggere dal disco, avere 7 processi extra in attesa della prossima lettura non aiuterà nulla.

E, mentre si utilizza un modulo di lettura CSV (se del stdlib csv o qualcosa di simile NumPy o Pandas) può essere una buona idea per semplicità, è improbabile fare molta differenza in termini di prestazioni.

Ancora, vale la pena controllare che davvero sono vincolato I/O, invece di solo indovinare. Esegui il tuo programma e verifica se l'utilizzo della CPU è vicino allo 0% o vicino al 100% o un core. Fai quello che Amadan ha suggerito in un commento ed esegui il tuo programma con il solo pass per l'elaborazione e verifica se questo taglia il 5% delle volte o il 70%. Potresti anche provare a confrontare un ciclo su os.open e os.read(1024*1024) o qualcosa del genere e vedere se è più veloce.


Dal momento che la vostra utilizzando Python 2.x, Python è affidamento sulla libreria stdio C a indovinare quanto a tampone in un momento, quindi potrebbe essere la pena costringendolo a tamponare di più. Il modo più semplice per farlo è utilizzare readlines(bufsize) per alcuni grandi bufsize. (Puoi provare numeri diversi e misurarli per vedere dove è il picco. Nella mia esperienza, di solito qualsiasi cosa da 64K-8MB è più o meno la stessa, ma dipende dal tuo sistema che potrebbe essere diverso, specialmente se stai leggendo ad esempio fuori un filesystem di rete con grande rendimento ma la latenza orribile che sommerge il throughput-vs-latenza del disco fisico reale e la memorizzazione nella cache del sistema operativo fa)

Così, per esempio:.

bufsize = 65536 
with open(path) as infile: 
    while True: 
     lines = infile.readlines(bufsize) 
     if not lines: 
      break 
     for line in lines: 
      process(line) 

Nel frattempo, supponendo che tu sia su un sistema a 64 bit, potresti provare a utilizzare mmap invece di leggere il file in primo luogo. Questo certamente non è garantito per essere migliore, ma è maggio essere migliore, a seconda del sistema.Ad esempio:

with open(path) as infile: 
    m = mmap.mmap(infile, 0, access=mmap.ACCESS_READ) 

un pitone mmap è una sorta di strano oggetto agisce come un str e come un file allo stesso tempo, in modo da poter, ad esempio, manualmente scansione iterazione per newlines, oppure si può chiamare readline su di esso come se fosse un file. Entrambi richiedono più elaborazione da Python che iterando il file come linee o facendo batch readlines (perché un loop che sarebbe in C ora è in puro Python ... anche se forse è possibile aggirare il problema con re, o con una semplice estensione Cython ?) ... ma il vantaggio I/O del sistema operativo sapendo che cosa stai facendo con la mappatura può invertire lo svantaggio della CPU.

Purtroppo, Python non espone la chiamata madvise che usereste per modificare le cose, nel tentativo di ottimizzare questo in C (ad esempio, impostando esplicitamente MADV_SEQUENTIAL invece di fare l'ipotesi del kernel, o forzare le pagine enormi trasparenti) - ma in realtà è possibile eseguire la funzione ctypes da libc.

+1

Grazie per aver dedicato del tempo a rispondere a questo in modo molto dettagliato :) +1 –

+0

Ho 30 GB di memoria nella finestra Linux. C'è qualche problema è fare un readlines() per prendere l'intero file in memoria? – Reise45

+0

@ Reise45: Dipende da cosa intendi per "problema". Dovrebbe funzionare_; 'readlines' su un file da 3 GB dovrebbe prendere meno di 4 GB, e se anche pre-processate tutte le linee in liste di valori in memoria, questo non dovrebbe essere superiore a 12 GB, quindi siete ancora entro i limiti. Ma significa che devi fare tutta la lettura in anticipo, quindi il sistema operativo non può fare da pipeline all'I/O in attesa e alla tua CPU; perdi tempo con malloc e errori di cache; ecc. Se ci sono stati alcuni vantaggi (ad esempio, ti permettono di usare NumPy per accelerare un ciclo di elaborazione lento), potrebbe valerne la pena, ma in caso contrario, perché farlo? – abarnert

Problemi correlati