Differenza tra programmazione parallela e concorrente?


44

Quando si guarda alla programmazione concorrente, vengono comunemente usati due termini, cioè simultaneo e parallelo.

E alcuni linguaggi di programmazione rivendicano specificamente il supporto per la programmazione parallela, come Java .

Ciò significa che la programmazione parallela e simultanea sono effettivamente diverse?


10
Sì, la programmazione simultanea e parallela sono diverse. ad esempio, è possibile avere due thread (o processi) in esecuzione contemporaneamente sullo stesso core tramite il cambio di contesto. Quando i due thread (o processi) vengono eseguiti su due diversi core (o processori), si ha parallelismo. Quindi, nel primo caso (la concorrenza) il parallelismo è solo "virtuale", mentre nel secondo hai un vero parallelismo. Pertanto, ogni programma parallelo è simultaneo, ma il contrario non è necessariamente vero.
Massimo Cafaro,

1
Stai attento qui. È possibile ottenere lo stesso risultato sia attraverso il supporto linguistico (ovvero estendendo una lingua con nuovi costrutti) sia utilizzando un approccio di basso livello (ad esempio, utilizzando una libreria, come nel caso di MPI e OpenMP). Ad ogni modo, con gli attuali processori multicore e sistemi operativi con supporto SMP, il programma che sarà concorrente se eseguito su vecchi processori single-core, può essere eseguito in parallelo se il sistema operativo pianifica i thread di esecuzione del programma su core diversi. Quindi, la distinzione è un po '"sfocata" al giorno d'oggi.
Massimo Cafaro,

3
Quello che usi per una velocità di costante di latenza della luce. In concomitanza fingi che la velocità di latenza della luce sia un ciclo di clock. Parallelamente si assume che un server sia accanto, in distribuito si assume che un server sia su Marte.


1
Robert Harper discute il problema in due post sul blog, "Il parallelismo non è concorrenza" e "Parallelismo e concorrenza, rivisitati" , che potresti voler controllare.
Basilio

Risposte:


26

Distingua il parallelismo (utilizzando unità di calcolo extra per svolgere più lavoro per unità di tempo) dalla concorrenza (gestendo l'accesso alle risorse condivise). Insegna innanzitutto il parallelismo perché è più facile e aiuta a stabilire una mentalità non sequenziale.

Da "A Sophomoric ∗ Introduzione al parallelismo e alla concorrenza della memoria condivisa" di Dan Grossman (versione del 16 novembre 2013)


21

Oltre alla risposta di Nish, vorrei raccomandare il libro di Simon Marlow su Parallel and Concurrent Programming in Haskell o il suo tutorial più breve . Rispondono alla tua prima domanda dal punto di vista di Haskell, quindi potrebbero essere più adatti ai lettori teoricamente inclini (Haskell è un linguaggio di programmazione puramente funzionale e pigro che è molto più vicino alla matematica rispetto ad altre lingue).

Citando da lì:

In molti campi, le parole parallele e concorrenti sono sinonimi; non così nella programmazione, dove sono usati per descrivere concetti fondamentalmente diversi.

Un programma parallelo è uno che utilizza una molteplicità di hardware computazionale (ad esempio più core del processore) per eseguire il calcolo più rapidamente. Parti diverse del calcolo sono delegate a processori diversi che vengono eseguiti contemporaneamente (in parallelo), in modo che i risultati possano essere consegnati prima che se il calcolo fosse stato eseguito in sequenza.

Al contrario, la concorrenza è una tecnica di strutturazione del programma in cui esistono più thread di controllo. In teoria i thread di controllo eseguono "allo stesso tempo"; cioè, l'utente vede i loro effetti interlacciati. Se eseguono effettivamente contemporaneamente o meno è un dettaglio di implementazione; un programma simultaneo può essere eseguito su un singolo processore attraverso l'esecuzione interfogliata o su più processori fisici.

Consiglio di leggere il resto nell'esercitazione (p. 4), ma lasciatemi citare parte del resto di questa sezione, in quanto collega entrambi i paradigmi di programmazione con le caratteristiche quantitative e qualitative dei programmi, come efficienza, modularità e determinismo.

Mentre la programmazione parallela riguarda solo l'efficienza, la programmazione concorrente riguarda la strutturazione di un programma che deve interagire con più agenti esterni indipendenti (ad esempio l'utente, un server di database e alcuni client esterni). La concorrenza consente a tali programmi di essere modulari; il thread che interagisce con l'utente è distinto dal thread che comunica con il database. In assenza di concorrenza, tali programmi devono essere scritti con loop e callback di eventi --- in effetti, i loop e i callback di eventi vengono spesso utilizzati anche quando è disponibile la concorrenza, poiché in molte lingue la concorrenza è troppo costosa o troppo difficile da uso.

La nozione di "fili di controllo" non ha senso in un programma puramente funzionale, perché non ci sono effetti da osservare e l'ordine di valutazione è irrilevante. Quindi la concorrenza è una tecnica di strutturazione per un codice efficace; in Haskell, questo significa codice nella monade IO.

Una distinzione correlata è tra i modelli di programmazione deterministica e non deterministica. Un modello di programmazione deterministica è quello in cui ciascun programma può dare un solo risultato, mentre un modello di programmazione non deterministico ammette programmi che possono avere risultati diversi, a seconda di alcuni aspetti dell'esecuzione. I modelli di programmazione simultanea sono necessariamente non deterministici, perché devono interagire con agenti esterni che causano eventi in tempi imprevedibili. Il non determinismo presenta alcuni notevoli svantaggi, tuttavia: i programmi diventano significativamente più difficili da testare e ragionare.

Per la programmazione parallela vorremmo usare, se possibile, modelli di programmazione deterministica. Poiché l'obiettivo è solo quello di arrivare alla risposta più rapidamente, preferiremmo non rendere più difficile il debug del nostro programma nel processo. La programmazione parallela deterministica è il migliore dei due mondi: test, debugging e ragionamento possono essere eseguiti sul programma sequenziale, ma il programma funziona più velocemente quando vengono aggiunti processori. In effetti, la maggior parte dei processori stessi implementa il parallelismo deterministico sotto forma di pipeline e unità di esecuzione multiple.

Mentre è possibile fare una programmazione parallela usando la concorrenza, questa è spesso una scelta sbagliata, perché la concorrenza sacrifica il determinismo. In Haskell, i modelli di programmazione parallela sono deterministici. Tuttavia, è importante notare che i modelli di programmazione deterministica non sono sufficienti per esprimere tutti i tipi di algoritmi paralleli; ci sono algoritmi che dipendono dal non determinismo interno, in particolare problemi che implicano la ricerca di uno spazio di soluzione. In Haskell, questa classe di algoritmi è espressibile solo utilizzando la concorrenza.


20

La valuta e il parallelismo differiscono nei problemi che risolvono e causano, ma non sono indipendenti.

Concorrenza

Eseguire due attività contemporaneamente significa che i singoli passaggi di entrambe le attività vengono eseguiti in modo intercalato. Se non si tiene conto del parallelismo, si può presumere che una sola istruzione venga eseguita in qualsiasi momento, ma non si ha (a priori) alcuna garanzia su quale compito debba eseguire il passaggio successivo.

Questo è utile sotto alcuni aspetti:

  • Programmazione più chiara di compiti indipendenti in un programma.
  • Permette di gestire IO durante il calcolo (ad es. Nella GUI).
  • Consente l'esecuzione di più di un programma alla volta (concorrenza a livello di sistema operativo).

Alcune delle principali sfide sono:

  • Mantenere la coerenza dei dati.
  • Evita deadlock e livelock .
  • Determinare la semantica precisa dei processi simultanei.
  • Determinare le proprietà statiche che garantiscono la correttezza.

Parallelismo

Eseguire due attività in parallelo significa che le istruzioni vengono eseguite contemporaneamente . Ciò è utile principalmente per:

  • Migliora la produttività del sistema eseguendo programmi in parallelo (ad es. Su sistemi multi core).
  • Migliora il tempo di esecuzione dei singoli programmi utilizzando più CPU contemporaneamente.
  • Utilizzare IO su molte macchine (ad esempio database distribuiti).

Le sfide principali includono:

  • Problemi di partizione che consentono e sviluppano algoritmi in grado di utilizzare il parallelismo.
  • Ridurre al minimo le dipendenze e la comunicazione tra le unità di calcolo.
  • Tutti i problemi causati dalla concorrenza: almeno dal punto di vista della memoria, i programmi paralleli sembrano simili a quelli simultanei a causa della serializzazione degli accessi alla memoria.
  • Gestire un supporto hardware non ottimale.

Vedi anche questa domanda per distinguere il calcolo parallelo e distribuito.


5

Una risposta leggermente idealizzata, forse ...

  • La concorrenza è una proprietà di come viene scritto un programma . Se un programma viene scritto usando costruzioni come forchette / join, blocchi, transazioni, operazioni atomiche di confronto e scambio e così via, allora è concorrente.

  • Il parallelismo è una proprietà di come viene eseguito un programma . Se un programma viene eseguito contemporaneamente su più di un'unità computazionale, viene eseguito in parallelo.


1

Ci sono molte risposte su questo, ma può essere fonte di confusione. Mi piace pensarlo in questo modo, e forse aiuta ?:

La programmazione concorrente è un codice a cui non interessa l'ordine di esecuzione. Java è un linguaggio scadente per la programmazione concorrente, ma ci sono librerie e framework per aiutare. JavaScript è un linguaggio eccellente per la programmazione concorrente ed è spesso difficile quando si desidera scrivere qualcosa che non è simultaneo (ad esempio, se si desidera forzare l'ordine di esecuzione). La programmazione concorrente è ottima per la programmazione basata su eventi (in cui l'ordine di esecuzione è determinato dai listener di eventi, come il codice in esecuzione nel browser che agisce quando si fa clic su un pulsante o si digita in una casella).

Un esempio potrebbe includere la creazione di un centinaio di richieste HTTP. In NodeJS, la soluzione più semplice è aprire tutte e 100 le richieste contemporaneamente con un metodo di callback e quando le risposte ritornano, ogni volta viene eseguito un metodo. Questa è una programmazione concorrente. In Ruby, la soluzione più semplice (più comune) è aprire una richiesta e gestire la risposta, aprire la richiesta successiva e gestire la risposta, ecc. Per molte richieste, NodeJS è più facile da eseguire in modo tempestivo, anche se devi essere facendo attenzione a non martellare il server o massimizzare le connessioni in uscita (facile da fare per errore). Puoi scrivere Ruby in modo simultaneo, ma non è come la maggior parte del codice Ruby è scritto, e fa un po 'male farlo.

Programmazione parallelaè un codice che può essere eseguito contemporaneamente in più thread o processi. Ciò consente di ottimizzare le prestazioni eseguendo il codice su più CPU (spesso includendo più macchine, come si potrebbe fare con qualcosa come Akka). Poiché NodeJS non è multi-thread e non c'è esecuzione parallela, non devi preoccuparti di scrivere codice thread-safe (e la maggior parte del codice JavaScript che ho visto non è thread-safe). In Java, anche se il linguaggio non rende la programmazione concorrente il modello normale, la programmazione parallela è molto integrata e spesso devi preoccuparti della sicurezza dei thread. Se stai scrivendo un sito Web in Java, in genere questo verrà eseguito in un contenitore che esegue ogni richiesta in un thread separato nella stessa memoria,


Alcuni dei precedenti dipendono dall'ambito e dai confini di cui stai parlando. Lavoro su siti Web. La maggior parte del codice Java che vedo non è una programmazione concorrente. Certo, se rimpicciolisci abbastanza, l'ordine in cui arrivano le richieste dei clienti non è importante, ma se ingrandisci ulteriormente, l'ordine in cui le cose vengono eseguite è dettato dal codice. Ma il codice è scritto in modo che le richieste possano essere eseguite in parallelo con molti oggetti condivisi che devono essere thread-safe.

Nel frattempo, la maggior parte del codice JavaScript che vedo è simultaneo: è scritto in modo che l'ordine di esecuzione non sia importante per molti livelli. Ma non è scritto per supportare l'esecuzione parallela nella memoria condivisa. Certo, puoi eseguire lo stesso codice in parallelo su più processi, ma gli oggetti non sono condivisi, quindi non è una programmazione parallela in alcun senso significativo.

Per ulteriori letture, mi piacciono molto le illustrazioni nella risposta in alto a questa domanda qui: https://www.quora.com/What-are-the-differences-b Between - parallel - concurrent - and - asynchronous-programming

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.