Modo efficiente per salvare i dati su disco durante l'esecuzione di un'attività intensiva dal punto di vista computazionale

StackOverflow https://stackoverflow.com/questions/1014113

Domanda

Sto lavorando a un software scientifico ad alta intensità di CPU (il suo limite proc), ma deve scrivere i dati su disco abbastanza spesso (i / o associato).

Sto aggiungendo parallelizzazione a questo (OpenMP) e mi chiedo quale sia il modo migliore per rispondere alle esigenze di scrittura su disco. Non c'è motivo per cui la simulazione debba attendere sull'HDD (che è quello che sta facendo ora).

Sto cercando una 'best practice' per questo, e la velocità è ciò che mi interessa di più (queste possono essere simulazioni estremamente lunghe).

Grazie ~ Alex

Primi pensieri:

Avere un processo separato esegue la scrittura effettiva su disco, quindi la simulazione ha due processi: uno è associato alla CPU (simulazione) e uno è associato all'IO (scrittura del file). Sembra complicato.

Forse una pipe / buffer? Sono un po 'nuovo per questi, quindi forse potrebbe essere una possibile soluzione.

È stato utile?

Soluzione

Se stai implementando OpenMP nel tuo programma, allora è meglio usare #pragma omp single o #pragma omp master dalla sezione parallela per salvare su file. Questi pragmi consentono a un solo thread di eseguire qualcosa. Quindi, il tuo codice potrebbe apparire come segue:

#pragma omp parallel
{
    // Calculating the first part
    Calculate();

    // Using barrier to wait all threads
    #pragma omp barrier

    #pragma omp master
    SaveFirstPartOfResults();

    // Calculate the second part
    Calculate2();

    #pragma omp barrier

    #pragma omp master
    SaveSecondPart();

    Calculate3();

    // ... and so on
}

Qui il team di thread eseguirà il calcolo, ma solo un singolo thread salverà i risultati sul disco.

Sembra una pipeline di software. Ti suggerisco di prendere in considerazione il modello tbb :: pipeline dalla libreria Intel Threading Building Blocks. Potrei rimandarti al tutorial sulle pipeline del software a http://cache-www.intel.com/cd/00/00/30/11/301132_301132.pdf#page=25 . Si prega di leggere il paragrafo 4.2. Hanno risolto il problema: un thread da leggere dall'unità, il secondo per elaborare le stringhe di lettura, il terzo da salvare sull'unità.

Altri suggerimenti

Direi che il modo migliore sarebbe generare un thread diverso per salvare i dati, non un processo completamente nuovo; con un nuovo processo, si crea il problema di dover comunicare i dati da salvare oltre il limite del processo, il che introduce una nuova serie di difficoltà.

La prima soluzione che mi viene in mente è praticamente ciò che hai detto: avere dischi scrive nel loro processo con una pipe a senso unico dalla sim allo scrittore. Lo scrittore scrive il più velocemente possibile (estraendo nuovi dati dalla pipe). Il problema è che se la sim si spinge troppo avanti rispetto allo scrittore, la sim bloccherà comunque sulla scrittura della pipe, e sarà collegata a I / O a una rimozione.

Il problema è che in effetti il ??tuo ciclo di simulazione non è completo finché non sputa i risultati.

La seconda cosa che mi viene in mente è usare l'I / O non bloccante. Ogni volta che la sim deve scrivere, dovrebbe farlo tramite I / O non bloccanti. Alla successiva necessità di scrivere, può quindi raccogliere i risultati della precedente operazione di I / O (eventualmente incorrere in una piccola attesa) prima di iniziare la nuova. Ciò mantiene la simulazione in esecuzione il più possibile in parallelo con l'I / O senza lasciare che la simulazione vada molto avanti rispetto alla scrittura.

La prima soluzione sarebbe migliore se il ciclo di elaborazione della simulazione varia (a volte più piccolo del tempo per una scrittura, a volte più lungo) perché in media le scritture potrebbero tenere il passo con la sim.

Se il ciclo di elaborazione sarà sempre (o quasi sempre) più breve del tempo di scrittura  quindi potresti anche non preoccuparti della pipe e usare semplicemente l'I / O non bloccante, perché se usi la pipe alla fine si riempirà e la sim verrà comunque bloccata sull'I / O.

Dato che sei associato alla CPU e all'IO: fammi indovinare: c'è ancora molta memoria disponibile, giusto?

In tal caso, è necessario bufferizzare i dati che devono essere scritti sul disco in memoria in una certa misura. Scrivere enormi quantità di dati è in genere molto più veloce rispetto alla scrittura di piccoli pezzi.

Per la scrittura stessa: considerare l'utilizzo di IO mappati in memoria. È passato un po 'di tempo da quando ho fatto un benchmark, ma l'ultima volta che l'ho fatto è stato significativamente più veloce.

Inoltre puoi sempre scambiare un po 'di CPU contro IO. Penso che tu stia attualmente scrivendo i dati come una sorta di dati grezzi, non compressi, giusto? È possibile ottenere alcune prestazioni IO se si utilizza un semplice schema di compressione per ridurre la quantità di dati da scrivere. La libreria ZLIB è abbastanza facile da lavorare e si comprime molto velocemente al livello di compressione più basso. Dipende dalla natura dei dati, ma se vi è molta ridondanza in esso anche un algoritmo di compressione molto rozzo può eliminare il problema di IO IO.

Un thread esegue continuamente una fase del processo ad alta intensità computazionale e quindi aggiunge il risultato parziale a una coda di risultati parziali. Un altro thread rimuove continuamente i risultati parziali dalla coda e li scrive sul disco. Assicurati di sincronizzare l'accesso alla coda. Una coda è una struttura di dati simile a un elenco in cui è possibile aggiungere elementi alla fine e rimuovere elementi dalla parte anteriore.

Rendi l'applicazione con due thread , uno per CPU e uno per il disco rigido.

Chiedere al thread della CPU di inserire i dati completati in una coda da cui il thread del disco rigido estrae quando arrivano i dati.

In questo modo la CPU si libera dei dati e consente a qualcun altro di gestirli e il disco rigido attende pazientemente qualsiasi dato nella sua coda.

Per quanto riguarda l'implementazione, potresti fare la coda come un tipo di oggetto di memoria condivisa, ma penso che una pipe sarebbe esattamente ciò che stai cercando. La CPU scrive semplicemente sulla pipe quando necessario. Sul lato del disco rigido, leggere semplicemente la pipe e ogni volta che si ottengono dati validi, procedere da lì.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top