Ho lavorato intensamente a livello di elaborazione in F #. Funzioni come Array.Parallel.map
che utilizzano la libreria parallela di attività .Net hanno velocizzato il mio codice in modo esponenziale per uno sforzo davvero minimo.F # PSeq.iter non sembra utilizzare tutti i core
Tuttavia, a causa di problemi di memoria, ho rifatto una sezione del mio codice in modo che possa essere pigramente valutata all'interno di un'espressione di sequenza (questo significa che devo memorizzare e passare meno informazioni). Quando è arrivato il momento di valutare che ho usato:
// processor and memory intensive task, results are not stored
let calculations : seq<Calculation> = seq { ...yield one thing at a time... }
// extract results from calculations for summary data
PSeq.iter someFuncToExtractResults results
Invece di:
// processor and memory intensive task, storing these results is an unnecessary task
let calculations : Calculation[] = ...do all the things...
// extract results from calculations for summary data
Array.Parallel.map someFuncToExtractResults calculations
Quando si utilizza una delle funzioni Array.Parallel posso vedere chiaramente tutti i core sul mio computer calcio in marcia (~ 100% di utilizzo della CPU). Tuttavia, la memoria extra richiesta significa che il programma non è mai stato completato.
Con la versione PSeq.iter quando eseguo il programma, c'è solo un utilizzo dell'8% della CPU (e un utilizzo minimo della RAM).
Quindi: C'è qualche motivo per cui la versione PSeq viene eseguita molto più lentamente? È a causa della valutazione pigra? C'è qualcosa di magico "essere parallelo" che mi manca?
Grazie,
Altre risorse, implementazioni del codice sorgente di entrambi (sembrano utilizzare diverse librerie parallele in .NET):
https://github.com/fsharp/fsharp/blob/master/src/fsharp/FSharp.Core/array.fs
https://github.com/fsharp/powerpack/blob/master/src/FSharp.PowerPack.Parallel.Seq/pseq.fs
EDIT: Aggiunto di più dettagli per codice esempi e dettagli
Codice:
Seq
// processor and memory intensive task, results are not stored let calculations : seq<Calculation> = seq { for index in 0..data.length-1 do yield calculationFunc data.[index] } // extract results from calculations for summary data (different module) PSeq.iter someFuncToExtractResults results
Array
// processor and memory intensive task, storing these results is an unnecessary task let calculations : Calculation[] = Array.Parallel.map calculationFunc data // extract results from calculations for summary data (different module) Array.Parallel.map someFuncToExtractResults calculations
Dettagli:
- La memorizzazione del Intermediat la versione dell'array viene eseguita rapidamente (fino a quando si arresta in modo anomalo) in meno di 10 minuti, ma utilizza ~ 70 GB di RAM prima che si blocchi (64 GB fisici, il resto paging)
- La versione seq impiega oltre 34 minuti e utilizza una frazione della RAM (solo circa 30 GB)
- C'è un miliardo di valori che sto calcolando. Quindi un miliardo di doppi (a 64 bit ciascuno) = 7.4505806 GB. Ci sono forme di dati più complesse ... e alcune copie non necessarie sto pulendo da qui l'attuale massiccia utilizzo della RAM.
- Sì l'architettura non è grande, la valutazione pigra è la prima parte di me cercando di ottimizzare il programma e/o lotto il backup dei dati in blocchi più piccoli
- Con un set di dati più piccolo, entrambi i pezzi di codice di uscita dello stesso risultati.
- @pad, ho provato quello che mi hai suggerito, il PSeq.iter sembrava funzionare correttamente (tutti i core attivi) quando alimentava il Calculation [], ma c'è ancora il problema della RAM (alla fine si è schiantato)
- sia la parte di riepilogo del codice che la parte di calcolo hanno un uso intensivo della CPU (principalmente perché di grandi insiemi di dati)
- Con la versione Seq ho solo lo scopo di parallelizzare una volta
La valutazione lenta non funziona correttamente con l'esecuzione parallela. Per essere onesti, passare lo stesso 'Calcolo []' a 'PSeq.iter' e' Array.Parallel.map'. È impossibile dire la ragione senza avere maggiori dettagli di 'Calculation' e' someFuncToExtractResults'. – pad
Grazie per il suggerimento, ho provato questo e PSeq si comporta bene quando dato l'array invece sul pigro seq ... tuttavia non risolve il problema RAM –