Strategie di I / O per problemi computazionali con set di dati di grandi dimensioni?


15

Il mio gruppo di ricerca si concentra sulla dinamica molecolare, che ovviamente può generare gigabyte di dati come parte di un'unica traiettoria che deve quindi essere analizzata.

Molti dei problemi di cui ci occupiamo riguardano correlazioni nel set di dati, il che significa che dobbiamo tenere traccia di grandi quantità di dati in memoria e analizzarli, piuttosto che utilizzare un approccio più sequenziale.

Quello che mi piacerebbe sapere è quali sono le strategie più efficienti per gestire l'I / O di insiemi di dati di grandi dimensioni in script. Normalmente utilizziamo script basati su Python perché rende la codifica del file I / O molto meno dolorosa di C o Fortran, ma quando abbiamo decine o centinaia di milioni di righe che devono essere elaborate, non è così chiaro quale sia l'approccio migliore . Dovremmo considerare di inserire il file in una parte del codice in C, oppure è un'altra strategia più utile? (Il precaricamento dell'intero array in memoria sarà migliore di una serie di letture sequenziali di "blocchi" (ordine di megabyte)?

Alcune note aggiuntive:

  • Siamo principalmente alla ricerca di strumenti di scripting per la post-elaborazione, piuttosto che strumenti "on-line", da cui l'uso di Python.

  • D=16limΔt(X(t+Δt)-X(t))2

Risposte:


6

Suppongo che la tua domanda derivi dall'osservazione che l'I / O causa un sovraccarico significativo in tutta la tua analisi. In tal caso, puoi provare a sovrapporre l'I / O con il calcolo.

Un approccio efficace dipende da come accedi ai dati e dal calcolo che esegui su tali dati. Se è possibile identificare un modello o se l'accesso a diverse aree dei dati è noto in precedenza, è possibile provare a precaricare i "blocchi successivi" di dati in background durante l'elaborazione dei "blocchi correnti".

Ad esempio, se attraversi il tuo file una sola volta ed elabori ciascuna riga o serie di righe, puoi dividere il flusso in blocchi di righe (o MB). Quindi, ad ogni iterazione sui blocchi, è possibile caricare il blocco i + 1 durante l'elaborazione del blocco i.

La tua situazione potrebbe essere più complessa e richiedere soluzioni più complesse. In ogni caso, l'idea è di eseguire l'I / O in background mentre il processore ha alcuni dati su cui lavorare. Se fornisci maggiori dettagli sul tuo problema specifico, potremmo essere in grado di approfondire;)

---- Versione estesa dopo aver fornito maggiori dettagli ----

Non sono sicuro di aver capito la notazione, ma bene, come hai detto, l'idea è un'interazione a tutti. Si dice anche che i dati potrebbero adattarsi alla RAM. Quindi, vorrei iniziare misurando il tempo per caricare tutti i dati e il tempo per eseguire il calcolo. Adesso,

  • se la percentuale di I / O è bassa (bassa come in te non ti interessa l'overhead, qualunque essa sia: 0,5%, 2%, 5%, ...), usa semplicemente l'approccio semplice: carica i dati subito e calcola. Risparmierai tempo per aspetti più interessanti della tua ricerca.

  • se non puoi permetterti il ​​sovraccarico potresti voler esaminare ciò che Pedro ha suggerito. Tieni presente ciò di cui Aron Ahmadia ha parlato e testalo prima di procedere a una completa implementazione.

  • se i precedenti non fossero soddisfacenti, sceglierei un'implementazione fuori core [1]. Poiché sembra che tu stia eseguendo calcoli su dati, c'è speranza :) Alcuni pseudocodici (supponendo che i risultati dell'analisi si adattino alla RAM):n2n

    carica chunk1 e chunk2
    per pezzi i = 1 a n
        caricare in modo asincrono il blocco i + 1
        per blocchi in j = i + 1 a n
            caricare in modo asincrono il blocco j + 1
            calcolare con blocchi i, j (* per la prima iterazione, questi sono i blocchi precaricati 1 e 2 *)

Nota: questo è pseudocodice veloce e sporco, bisognerebbe regolare gli indici.

Per implementarlo, è comune usare il cosiddetto doppio buffering . In parole povere: dividere la memoria in due aree di lavoro; mentre i dati vengono caricati in background nell'area di lavoro 1, il processore sta elaborando i dati nell'area di lavoro 2. Ad ogni iterazione, scambia il ruolo.

Mi dispiace non poter trovare un buon riferimento in questo momento.

[1] Un algoritmo out-of-core incorpora alcuni meccanismi per gestire (in modo efficiente) i dati che risiedono sul disco. Sono chiamati out-of-core anziché in-core ("in-RAM").


7

In precedenza ho avuto a che fare con problemi simili e la mia soluzione preferita è utilizzare l' I / O mappato in memoria , anche se in C ...

Il principio alla base è abbastanza semplice: invece di aprire un file e leggere da esso, lo carichi direttamente nella memoria e accedi ad esso come se fosse un array enorme. Il trucco che lo rende efficiente è che il sistema operativo in realtà non carica il file , lo tratta solo come memoria sostituita che deve essere caricata. Quando si accede a un determinato byte nel file, la pagina di memoria per quella parte del file viene scambiata in memoria. Se continui ad accedere a diverse parti del file e la memoria si restringe, le parti meno utilizzate verranno sostituite automaticamente - automagicamente!

Una rapida ricerca su Google mi dice che questo è disponibile anche per Python: 16.7. mmap - Supporto per file mappati in memoria , ma non so abbastanza su Python per dire se è davvero la stessa cosa.


1
Assicurati solo di misurare e testare prima di implementare qualcosa di simile mmapnel tuo codice principale. Molti sistemi operativi moderni offrono prestazioni simili tra normali readcon meno complicazioni. (Inoltre, sì, mmap in Python fornisce un'interfaccia portatile per le mappe di memoria di Windows e UNIX).
Aron Ahmadia,

1

Forse potresti usare Cython nelle sezioni I / O dei tuoi file e convertire questa parte in codice C?

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.