Linguaggio di sviluppo software di calcolo scientifico parallelo?


18

Voglio sviluppare un software di calcolo scientifico parallelo da zero. Voglio alcuni pensieri su quale lingua iniziare. Il programma prevede la lettura / scrittura di dati in file txt e l'esecuzione di calcoli pesanti in parallelo, con molte fattorizzazioni LU e l'uso di solutori lineari sparsi. Le soluzioni candidate che stavo pensando sono Fortran 2003/2008 con OpenMP o co-array, C ++ con openmp cilk + o TBB, python. Qualsiasi altro suggerimento documentato è il benvenuto! Conosco molto bene C, Fortran e Java (in questo ordine). Ho fatto alcuni script in Python ma roba di base.

So che fortran è molto veloce, ma difficile da mantenere e parallelizzare. Si dice che C ++ sia lento se non si usano librerie esterne, ecc. Python mi piace, ma è realistico scrivere un software di livello industriale su larga scala?

Il software deve essere in grado di gestire grandi quantità di dati ed essere efficace con calcoli scientifici. La performance è essenziale.

Per lo sfondo, ho già un software funzionante scritto in Fortran. Molte persone sono state coinvolte nello sviluppo per molti anni e il codice è davvero sporco. Mantenere e parallelizzare il codice si è rivelato un incubo e sto pensando a delle alternative.

Petros


5
In quanto C ++ wink, non definirei Fortran difficile da mantenere. La manutenibilità è per lo più legata alle buone pratiche, non alla scelta della lingua. La lentezza del C ++ è ipervenduto. Inoltre, ti consiglio di aumentare questo post per descrivere le dimensioni dei dati e i tempi di consegna. Ho visto "grandi" variare di 9 o 10 ordini di grandezza a seconda di chi sto parlando.
Bill Barth,

@BillBarth Il problema con il codice Fortran esistente è che tre persone sono state coinvolte usando pratiche diverse. Vengo da uno sfondo C, un ragazzo da F77 e un altro da Matlab. I dati non sono allocabili e dimensionati per il sistema di dimensioni più grandi (sono stato coinvolto di recente). Il codice è stato in grado di simulare un sistema con 72000 equazioni algebriche differenziali e 74000 su un orizzonte temporale di 240 secondi in 350 secondi (tempo trascorso). L'ho ridotto a 170 secondi usando OpenMP per parallelizzare. Ora ho bisogno di eseguire diversi casi in parallelo (per spazzare per controllo di sicurezza).
electrique,

4
@BillBarth è troppo modesto nel vendere le sue abilità in C ++, ma è anche troppo generoso nella sua affermazione che "la lentezza del C ++ è ipervenduta". Ci sono stati diversi thread C ++ vs Fortran in scicomp.stackexchange.com che hanno discusso proprio di questa domanda e la conclusione generale è che semplicemente non è più vero che C ++ è più lento di Fortran in quasi tutti i casi. Personalmente penso che oggi potrebbe essere considerato un mito urbano. Ciò che è veramente vero è che se si tiene conto della manutenibilità del codice, Fortran oggi non va molto bene.
Wolfgang Bangerth,

2
@BillBarth e altri, se desideri continuare a discutere i meriti generali di Fortran, C ++ e altre lingue, ti preghiamo di portarlo nella chat room di scicomp e di chiunque desideri indirizzare in modo specifico.
Aron Ahmadia,

1
@AronAhmadia: ah, dai, ho così tanto da dire a Jed ;-) (Jed: un'altra volta. Nel nostro caso, nessun STL per matrici sparse, ma molto nelle strutture di dati mesh adattive.)
Wolfgang Bangerth,

Risposte:


19

Lasciami provare a scomporre le tue esigenze:

  • manutenibilità
  • Lettura / scrittura di dati di testo
  • Interfacce / capacità avanzate per le fattorizzazioni LU
  • Solutori lineari sparsi
  • Prestazioni e scalabilità per dati di grandi dimensioni

Da questo elenco, prenderei in considerazione le seguenti lingue:

C, C ++, Fortran, Python, MATLAB, Java

Julia è una nuova lingua promettente, ma la comunità si sta ancora formando attorno ad essa e non è stata implementata in nessun nuovo importante codice.

Lettura / scrittura di dati di testo

Questo è facile da ottenere in qualsiasi linguaggio di programmazione. Assicurati di eseguire il buffering e la coalescenza appropriati del tuo accesso I / O e otterrai buone prestazioni da qualsiasi delle lingue che dovresti prendere in considerazione. Evita gli oggetti stream in C ++ se non sai come usarli in modo performante.

Interfacce / capacità avanzate per le fattorizzazioni LU

Se si stanno eseguendo fattorizzazioni LU dense, è necessario utilizzare LAPACK o ScaLAPACK / Elemental per funzionalità parallele. LAPACK e ScaLAPACK sono scritti in Fortran, Elemental è scritto in C ++. Tutte e tre le librerie sono performanti, ben supportate e documentate. Puoi interfacciarti da una qualsiasi delle lingue che dovresti considerare.

Solutori lineari sparsi

I principali risolutori lineari sparsi liberamente disponibili sono quasi tutti disponibili tramite PETSc , scritto in C, che è ben documentato e supportato. È possibile interfacciarsi in PETSc da una qualsiasi delle lingue da considerare.

Prestazioni e scalabilità per dati di grandi dimensioni

Gli unici paradigmi di programmazione parallela che menzioni sono basati sulla memoria condivisa, il che significa che non stai prendendo in considerazione un approccio informatico basato su MPI (passaggio di messaggi) e di memoria distribuita. Nella mia esperienza, è molto più semplice scrivere codice che si ridimensiona ben oltre una dozzina di core usando una soluzione di memoria distribuita. Quasi tutti i "cluster" universitari sono basati su MPI in questi giorni, le grandi macchine a memoria condivisa sono costose e di conseguenza rare. Dovresti considerare MPI per il tuo approccio, ma il mio consiglio si applicherà indipendentemente dal paradigma di programmazione che scegli.

Per quanto riguarda le prestazioni sul nodo, se si scrivono routine numeriche da soli, è più semplice ottenere buone prestazioni seriali in Fortran. Se hai un po 'di esperienza in C, C ++ o Python, puoi ottenere prestazioni molto comparabili (C e C ++ sono morti, anche con Fortran, Python e MATLAB arrivano in circa il 25% di tempo in sovraccarico senza molto sforzo). MATLAB lo fa attraverso un compilatore JIT e un'ottima espressività algebrica lineare. Probabilmente dovrai usare i kernel numerici Cython, numpy, numexpr o embed per ottenere le prestazioni dichiarate da Python. Non posso commentare le prestazioni di Java, perché non conosco molto bene la lingua, ma sospetto che non sia lontano da quello di Python se scritto da un esperto.

Una nota sulle interfacce

Spero di averti convinto che sarai in grado di fare tutto ciò che desideri in uno dei linguaggi di programmazione che stai prendendo in considerazione. Se stai usando Java, le interfacce C saranno un po 'impegnative. Python ha un eccellente supporto dell'interfaccia C e Fortran tramite ctypes, Cython e f2py. LAPACK è già confezionato e disponibile tramite scipy. MATLAB ha tutte le funzionalità necessarie nelle sue librerie native, ma non è facilmente scalabile o particolarmente facile da eseguire sui cluster. Java può supportare le interfacce C e Fortran con JNI , ma non si trova comunemente nei cluster e nei software paralleli per il calcolo scientifico.

manutenibilità

Gran parte di questo si ridurrà al gusto personale, ma il consenso generale sulla manutenibilità è che si desidera ridurre al minimo il numero di righe di codice nel proprio software, scrivere codice modulare con interfacce ben definite e, per il software di calcolo, fornire test che verificano la correttezza e la funzionalità dell'implementazione.

Raccomandazione

Io personalmente ho avuto molta fortuna con Python e lo consiglio per molti progetti computazionali. Penso che dovresti prenderlo fortemente in considerazione per il tuo progetto. Python e MATLAB sono probabilmente i linguaggi più espressivi disponibili per il calcolo scientifico. Puoi facilmente interfacciare Python con qualsiasi altro linguaggio di programmazione, puoi usare f2py per racchiudere la tua attuale implementazione Fortran e riscrivere pezzo per pezzo qualunque parte desideri in Python verificando che tu stia mantenendo la funzionalità. In questo momento, consiglierei una combinazione dell'implementazione ufficiale di Python 2.7 con scipy . Puoi iniziare molto facilmente con questo stack dalla distribuzione di Python Enthought disponibile gratuitamente .

Puoi anche fare la maggior parte di questo in C, C ++ o Fortran. C e C ++ sono linguaggi molto interessanti per gli sviluppatori professionisti con molta esperienza, ma spesso inciampano nuovi sviluppatori e in questo senso probabilmente non sono una grande idea per un codice più accademico. Fortran e MATLAB sono popolari nel calcolo accademico, ma sono deboli nelle strutture dati avanzate e nell'espressività offerte da Python (pensate ad un oggetto dict Python, per esempio).

Domande correlate:


1
Una risposta tutto compreso molto ben documentata. Sotto Fortran uso molto Lapack. Daremo un'occhiata a Python e cercherò di avvolgere il mio codice Fortran per cominciare e lentamente mi sposterò su Python. L'unica cosa che mi spaventa è il 25% di tempo che potrei avere. Ma se si tratta del vantaggio di un codice più espressivo e di una migliore gestione del calcolo parallelo, ci proverò. Ho citato la memoria condivisa solo perché il software attualmente funziona in modo interattivo (apportare una modifica ai dati e rieseguire) su computer con memoria condivisa 2,4,8,24,48 core di ricercatori in Uni su Windows e Linux.
electrique,

3
Non so come si possa pretendere un overhead del 25% per i kernel numerici scritti in Python. I kernel numerici Python puri sono spesso dell'ordine di 100 volte più lenti di C. Numpy e numexpr possono fare un lavoro decente con determinate espressioni, ma difficilmente si scrivono nuovi kernel numerici in Python. Cython può rendere alcune cose veloci, ma di solito non entro il 25% di C. Python è un bel linguaggio "colla", ma penso che Aron lo stia vendendo come una soluzione per scopi generali per compiti sensibili alle prestazioni.
Jed Brown,

L'I / O è il punto debole di Fortran, perché Fortran richiede molta struttura nell'I / O. La mia esperienza di seconda mano nel parlare con i colleghi del mio laboratorio che lavorano con Cython corrisponde a ciò che Jed dice di Cython; almeno uno di essi scrive C sintonizzato a mano per sostituire Cython per attività ad alte prestazioni, e quindi credo che le prestazioni di Python che chiamano il codice C risultante siano più vicine alla richiesta di Aron. Inoltre, se hai intenzione di menzionare PETSc e Python, potresti anche menzionare petsc4py. L'ultima volta che l'ho visto (alcuni anni fa), non c'erano buone interfacce MPI per Java. È cambiato?
Geoff Oxberry,

@GeoffOxberry: esistono i collegamenti MPI Java ma non sono stati aggiornati in quasi un decennio. Considero il loro status dubbio. Fortran ha numerose opzioni I / O che possono essere fatte per andare molto rapidamente. Consiglio di esplorare Parallel HDF5 (e HDF5, in generale). Se l'I / O è veramente dominante (oltre il 50% del tempo di esecuzione), potrebbero essere necessarie misure più serie, ma per il resto la qualità e la portabilità dell'interfaccia simile a quella di HDF valgono probabilmente la pena.
Bill Barth,

@BillBarth: dovrò verificarlo. Il mio commento su Fortran I / O proviene dal punto di vista di qualcuno che una volta mi consiglia di scrivere un parser di file di input in Fortran. È possibile, applicando una grande quantità di struttura, ma non ho visto il parser regex o le librerie di parser XML facilmente e ampiamente utilizzate in Fortran (per fare alcuni esempi). C'è una buona ragione per questo: siamo le uniche persone che usano più Fortran. Forse stiamo pensando a diversi casi d'uso.
Geoff Oxberry,

2

Oltre alla risposta molto completa di Aron, darei un'occhiata ai vari thread su scicomp.stackexchange che si occupavano della domanda su quale linguaggio di programmazione prendere - sia per quanto riguarda la velocità dei programmi che per quanto riguarda la facilità o la difficoltà è scrivere e mantenere software in queste lingue.

Detto questo, oltre a ciò che è stato scritto lì, vorrei fare alcune osservazioni:

(i) Includete il co-array Fortran nell'elenco. Per quanto ne so, il numero di compilatori che lo supportano in realtà è molto piccolo - e il mio, in realtà, è zero. Il compilatore Fortran più ampiamente disponibile è GNU gfortran, e mentre le attuali fonti di sviluppo analizzano un sottoinsieme di co-array, credo che in realtà non ne supporti nessuno (cioè accetta la sintassi ma non implementa alcuna semantica) . Questa è ovviamente un'osservazione generale sui nuovi standard Fortran: che il ritardo con cui i compilatori supportano effettivamente i nuovi standard viene misurato in diversi anni - i compilatori hanno implementato completamente Fortran 2003 negli ultimi due anni e supportano solo parzialmente Fortran 2008. Questo non dovrebbe impedirti di utilizzarlo se hai un compilatore che supporta ciò che usi,

(ii) Lo stesso è certamente vero con C ++ / Cilk +: Sì, Intel lo sta sviluppando su un ramo di GCC, ma non è disponibile in nessuna delle versioni di GCC e, probabilmente, non lo sarà per un po '. Puoi aspettarti che ci vorranno altri 2-3 anni almeno finché non troverai Cilk + con le versioni di GCC installate su macchine linux tipiche.

(iii) C ++ / TBB è una storia diversa: il TBB è in circolazione da un po 'di tempo, ha un'interfaccia molto stabile ed è compilabile con la maggior parte di qualsiasi compilatore C ++ che esiste negli ultimi anni (sia su Linux che su Windows) . Lo stiamo usando da vicino.II già da diversi anni con buoni risultati. C'è anche un ottimo libro su di esso.

(iv) Ho la mia opinione su OpenMP, vale a dire che si tratta di una soluzione alla ricerca di un problema. Funziona bene per parallelizzare i circuiti interni che è ciò che potrebbe essere interessante se si dispone di strutture di dati molto regolari. Ma raramente è ciò che vuoi fare se devi parallelizzare qualcosa - perché ciò che vuoi davvero fare è parallelizzare i loop esterni . E per questo, soluzioni come TBB sono soluzioni molto migliori perché usano i meccanismi del linguaggio di programmazione piuttosto che cercare di descrivere cosa succede al di fuori del linguaggio (tramite #pragmas) e in modo tale da non avere accesso agli handle di thread , indicatori di stato dei risultati, ecc., all'interno del programma.

(v) Se sei sperimentale, potresti anche dare un'occhiata ai nuovi linguaggi di programmazione progettati per la programmazione parallela e, in particolare, per attività come quelle che descrivi. Ci sono essenzialmente due che darei un'occhiata: X10 e Chapel . Ho visto dei simpatici tutorial su Chapel, e sembra ben progettato, sebbene entrambi oggi siano anche soluzioni insulari.


Per la cronaca, Intel afferma di avere un co-array Fortran in parallelo (memoria distribuita) integrato nei loro attuali compilatori. Stiamo esaminando il TACC, ma non ho ancora nulla da segnalare. Cray ha anche un'implementazione nel loro compilatore, ma questo è disponibile solo su un piccolo numero intero di macchine in tutto il mondo. Non credo che nessuno abbia ancora implementato l'intero standard Fortran 2008 per quanto riguarda i co-array, ma in alcuni compilatori c'è qualcosa di più del supporto nascente. Cilk + è, ovviamente, disponibile anche con i compilatori Intel, ma probabilmente fare affidamento non è ancora saggio.
Bill Barth,

Lo standard Fortran 2008 non è stato approvato fino alla fine del 2010, quindi passeranno alcuni anni prima che il CAF sarà ampiamente disponibile. G95 in realtà aveva un'implementazione (non gratuita) ma non è più sviluppato (lo sviluppatore si era unito a PathScale).
Stali,

La maggior parte di g95 alla fine è finita in gfortran ma è possibile che CAF non ne faccia parte.
Wolfgang Bangerth,

Credo che il compilatore Intel offra un buon supporto al co-array. L'hanno costruito usando mpiexec. Non sarà la mia prima scelta. La cosa bella è che la stessa implementazione può essere eseguita su memoria condivisa e distribuita (ho eseguito alcuni test). Con i processori opteron a memoria condivisa che raggiungono i 60 core a prezzi davvero ragionevoli, voglio prima vedere le mie opzioni di memoria condivisa.
electrique,

2

In generale, se sei davvero serio su questo progetto software, suggerirei una riscrittura completa in qualunque lingua tu ti senta più a tuo agio. Sembra che farai il lavoro da solo, e quindi otterrai i migliori risultati nella lingua con cui ti senti più a tuo agio.

Più specificamente, tuttavia, per quanto riguarda il parallelismo, ti incoraggio a provare a pensare un po 'fuori dagli schemi. OpenMP ha i suoi punti di forza, ma è bloccato nella mentalità di prendere un codice sequenziale e schiaffeggiare il parallelismo qua e là. Lo stesso vale, in sostanza, per Intels TBB.

Cilk è sicuramente un passo nella giusta direzione, cioè ti costringe a ripensare il tuo problema / soluzione in una configurazione intrinsecamente parallela. Quello che non mi piace, però, è che è ancora un'altra lingua . Inoltre, poiché può dedurre solo approssimativamente le relazioni tra compiti paralleli, lo scheduler può essere abbastanza conservativo e potrebbe non adattarsi bene a determinati problemi.

La buona notizia è, tuttavia, che, ancora una volta, se sei serio sulla tua implementazione, puoi fare ciò che Cilk fa, ad esempio riscrivere il tuo problema come un insieme di attività interdipendenti e distribuirle su un numero di processori / core, da soli o usando pthreads o usando impropriamente OpenMP per generare processi. Un bell'esempio di come ciò può essere fatto è lo schedulatore QUARK utilizzato nella libreria PLASMA . Un bel confronto tra le sue prestazioni e Cilk è dato qui .


Guarderò i link suggeriti. Il documento di confronto è molto bello! Grazie! Ho pensato a pthreads ma voglio che il programma sia multipiattaforma. Da quello che so pthreads ha problemi sotto Windows (sbagliato?).
electrique,

@ p3tris: la "p" in pthreads è per POSIX, quindi è il più portatile possibile. Esistono alcune implementazioni di Windows conformi come pthreads-win32o all'interno del cygwinprogetto.
Pedro,

Sulla base di stackoverflow.com/q/2797690/801468 vedo che ci sono molte cose necessarie per risolvere il problema per usarlo. Dato che non sono un programmatore, preferirei continuare con qualcosa di più testato.
electrique,

2

C'è stata una piccola discussione su Coarray Fortran nei commenti sopra. In questo momento, e per mia conoscenza limitata, il supporto del coarray nei compilatori è approssimativamente il seguente:

  • Cray ha un compilatore che supporta almeno le funzionalità di base del coarray. L'ho usato per scrivere codice che doveva essere "educativo", ma direi che potresti scrivere codice reale in Coarray Fortran. La sintassi e i concetti sono per lo più molto più semplici dell'MPI, ma come sempre ci sono molte trappole e le trappole sono diverse dall'MPI.
  • Intel fortran ha il supporto di coarray integrato nella libreria MPI. Presumibilmente questo limita le loro prestazioni teoriche di picco, ma non ho visto alcuna metrica.
  • Gfortran supporta i coarrays, ma solo per una singola immagine (o un singolo rango, in termini di MPI). Pertanto, non è disponibile alcuna vera parallelizzazione fino a quando gfortran 4.8 o 4.9 non sarà disponibile.

In generale, starei attento se avvii un codice basato su Coarray. La sintassi è semplice e molto più conveniente di Fortran / C / C ++ con MPI, ma non è altrettanto completa. Ad esempio, MPI supporta molte operazioni di riduzione ecc. Che potrebbero essere molto convenienti per te. Dipenderebbe davvero dal tuo bisogno di molta comunicazione. Se vuoi un esempio, fammi sapere e posso fornirti alcuni, se riesco a scavare i file.


Sì, ulteriori informazioni sulla prontezza di Coarray Fortran per questo tipo di problema sarebbero sicuramente utili. Benvenuto in scicomp!
Aron Ahmadia,

1

Dai un'occhiata a Spark è un framework distribuito per i calcoli in memoria che sfrutta la programmazione funzionale. La struttura di un programma in Spark è molto diversa rispetto a MPI, in pratica si scrive un codice come per un singolo computer, che viene automaticamente distribuito come funzioni ai dati presenti nella memoria. Supporta Scala, Java e Python.

Regressione logistica (scala):

//load data to distributed memory
val points = spark.textFile(...).map(parsePoint).cache()
var w = Vector.random(D) // current separating plane
for (i <- 1 to ITERATIONS) {
  val gradient = points.map(p =>
    (1 / (1 + exp(-p.y*(w dot p.x))) - 1) * p.y * p.x
  ).reduce(_ + _)
  w -= gradient
}
println("Final separating plane: " + w)

C'è un'estensione chiamata MLib (libreria di Machine Learning) che utilizza una libreria Fortran per alcuni calcoli di basso livello (per Python suppongo che sia usato numpy). Quindi, l'idea è semplice, concentrati sul tuo algoritmo e lascia le ottimizzazioni a livelli inferiori (ordine di elaborazione, distribuzione dei dati, ecc.).

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.