Sono due frasi che descrivono la stessa cosa da (leggermente) punti di vista diversi. La programmazione parallela sta descrivendo la situazione dal punto di vista dell'hardware: ci sono almeno due processori (possibilmente all'interno di un singolo pacchetto fisico) che lavorano su un problema in parallelo. La programmazione concorrente sta descrivendo le cose più dal punto di vista del software: due o più azioni possono avvenire contemporaneamente (contemporaneamente).
Il problema qui è che le persone stanno cercando di usare le due frasi per fare una chiara distinzione quando nessuna esiste davvero. La realtà è che la linea di demarcazione che stanno cercando di tracciare è stata sfocata e indistinta per decenni e nel tempo è diventata sempre più indistinta.
Quello che stanno cercando di discutere è il fatto che una volta, la maggior parte dei computer aveva una sola CPU. Quando hai eseguito più processi (o thread) su quella singola CPU, la CPU eseguiva davvero solo un'istruzione da uno di quei thread alla volta. L'aspetto della concorrenza era un'illusione: il passaggio della CPU tra l'esecuzione di istruzioni da diversi thread abbastanza rapidamente da quello alla percezione umana (a cui qualcosa di meno di 100 ms circa sembra istantaneo) sembrava che stesse facendo molte cose contemporaneamente.
L'ovvio contrasto con questo è un computer con più CPU o una CPU con più core, quindi la macchina sta eseguendo istruzioni da più thread e / o processi esattamente allo stesso tempo; l'esecuzione di un codice non può / non ha alcun effetto sull'esecuzione del codice nell'altro.
Ora il problema: una distinzione così chiara ha quasi mai esistita. I progettisti di computer sono in realtà abbastanza intelligenti, quindi hanno notato molto tempo fa che (ad esempio) quando era necessario leggere alcuni dati da un dispositivo I / O come un disco, ci è voluto molto tempo (in termini di cicli della CPU) per finire. Invece di lasciare la CPU inattiva mentre ciò accadeva, hanno escogitato vari modi per consentire a un processo / thread di effettuare una richiesta I / O e lasciare che il codice di qualche altro processo / thread venga eseguito sulla CPU mentre la richiesta I / O è stata completata.
Quindi, molto prima che le CPU multi-core diventassero la norma, abbiamo avuto operazioni da più thread in parallelo.
Questa è solo la punta dell'iceberg. Decenni fa, i computer hanno iniziato a fornire anche un altro livello di parallelismo. Ancora una volta, essendo persone abbastanza intelligenti, i progettisti di computer hanno notato che in molti casi avevano istruzioni che non si influenzavano a vicenda, quindi era possibile eseguire più di una istruzione dallo stesso flusso contemporaneamente. Un primo esempio che divenne abbastanza noto fu il Control Data 6600. Questo fu (con un margine abbastanza ampio) il computer più veloce del mondo quando fu introdotto nel 1964 - e gran parte della stessa architettura di base rimane oggi in uso. Tracciava le risorse utilizzate da ciascuna istruzione e disponeva di una serie di unità di esecuzione che eseguivano le istruzioni non appena le risorse da cui dipendevano diventavano disponibili, molto simili al design dei più recenti processori Intel / AMD.
Ma (come dicevano gli spot pubblicitari) aspetta - non è tutto. C'è ancora un altro elemento di design per aggiungere ulteriore confusione. Gli sono stati dati diversi nomi (ad es. "Hyperthreading", "SMT", "CMP"), ma tutti fanno riferimento alla stessa idea di base: una CPU che può eseguire più thread contemporaneamente, usando una combinazione di alcune risorse che sono indipendenti per ogni thread e alcune risorse condivise tra i thread. In un caso tipico questo è combinato con il parallelismo a livello di istruzione descritto sopra. Per fare ciò, abbiamo due (o più) set di registri di architettura. Quindi abbiamo una serie di unità di esecuzione che possono eseguire le istruzioni non appena le risorse necessarie diventano disponibili.
Quindi, ovviamente, arriviamo ai sistemi moderni con più core. Qui le cose sono ovvie, vero? Abbiamo N (da qualche parte tra 2 e 256 o giù di lì, al momento) nuclei separati, che possono eseguire tutte le istruzioni contemporaneamente, quindi abbiamo un caso ben definito di parallelismo reale - l'esecuzione di istruzioni in un processo / thread no ' influenzano l'esecuzione delle istruzioni in un altro.
Beh, in un certo senso. Anche qui abbiamo alcune risorse indipendenti (registri, unità di esecuzione, almeno un livello di cache) e alcune risorse condivise (in genere almeno il livello più basso di cache, e sicuramente i controller di memoria e la larghezza di banda in memoria).
Riassumendo: i semplici scenari che le persone amano contrastare tra risorse condivise e risorse indipendenti non accadono praticamente mai nella vita reale. Con tutte le risorse condivise, finiamo con qualcosa come MS-DOS, in cui possiamo eseguire solo un programma alla volta e dobbiamo smettere di eseguirne uno prima di poter eseguire l'altro. Con risorse completamente indipendenti, abbiamo N computer che eseguono MS-DOS (senza nemmeno una rete per collegarli) senza la possibilità di condividere nulla tra loro (perché se possiamo persino condividere un file, beh, è una risorsa condivisa, un violazione della premessa di base di non condividere nulla).
Ogni caso interessante comporta una combinazione di risorse indipendenti e risorse condivise. Ogni computer ragionevolmente moderno (e molti altri che non sono affatto moderni) ha almeno una certa capacità di eseguire almeno alcune operazioni indipendenti contemporaneamente, e quasi tutto ciò che è più sofisticato di MS-DOS ne ha sfruttato almeno qualche grado.
La bella e netta divisione tra "concorrente" e "parallelo" che alla gente piace disegnare non esiste e quasi mai lo è. Ciò che alla gente piace classificare come "concorrente" di solito comporta ancora almeno uno e spesso più diversi tipi di esecuzione parallela. Quello che a loro piace classificare come "parallelo" spesso comporta la condivisione di risorse e (ad esempio) un processo che blocca l'esecuzione di un altro mentre utilizza una risorsa condivisa tra i due.
Le persone che cercano di tracciare una netta distinzione tra "parallelo" e "concorrente" vivono in una fantasia di computer che non sono mai esistiti.