2009-09-01 12 views

risposta

8

Non posso parlare specificamente di Clojure, ma ... significa che non è necessario aspettare che qualcuno abbia finito con qualcosa prima di poter andare al lavoro. Che è grandioso.

In genere è realizzato con tipi immutabili. Se non è possibile modificare nulla, non è necessario attendere fino a quando qualcun altro non lo ha fatto prima di poterlo accedere.

+2

Chi è "qualcuno"? Potresti fare un esempio? Non penso ci sia qualcuno che condivide i miei oggetti con me. Forse dovrei controllare sotto il letto. –

+4

* qualcuno * è solo un altro pezzo di codice, in un altro thread, che accede a quell'oggetto. –

+0

Talvolta è più veloce a volte più lento, come la maggior parte delle ottimizzazioni eseguite senza misurare. Quindi a volte è una buona cosa, ea volte quelle serrature sarebbero andate meglio. Questo è il motivo per cui siamo chiamati software ** ingegneri **. – Eloff

5

Deadlock. O per essere più corretto la mancanza di loro.

Uno dei maggiori problemi nella maggior parte delle lingue è che si finisce con situazioni di stallo che sono:

  1. inferno sulla terra per eseguire il debug.
  2. Difficile essere sicuri di essersi sbarazzati.

Ora senza serrature, ovviamente non si incontrano deadlock.

+0

Non ho mai riscontrato un deadlock di cui ero a conoscenza. Sta succedendo più frequentemente di quanto mi rendo conto forse? Immagino di non avere familiarità con questo problema anche se ho programmato molto. Gli unici problemi di blocco di cui ero a conoscenza erano nel database. –

+0

@i_like_monkeys Se si sta scrivendo un Web frontend in C#, la maggior parte dei problemi di blocco si troveranno nei livelli inferiori (il server web e il database), ma se si svilupperanno programmi che sono sicuramente un problema. – tomjen

+0

Se si dispone di un deadlock, il sintomo di solito è che il programma si blocca (0% di utilizzo della CPU, nessuna delle sue attività viene eseguita, mai più, fino a quando non la si uccide manualmente con Task Manager o ecc.). Si verificano deadlock se i thread contengono più di un blocco alla volta e thread diversi acquisiscono i blocchi in un ordine diverso. –

1

Il vantaggio della concorrenza senza chiave è la mancanza di complessità nel programma. In linguaggi imperativi, la programmazione concorrente fa affidamento sui blocchi e una volta che il programma si insinua anche in bug moderatamente complessi e difficilmente risolvibili.

+0

Ti è mai successo? –

9

La concorrenza senza blocco offre anche il vantaggio che i lettori di non devono mai attendere altri lettori . Ciò è particolarmente utile quando molti thread leggeranno i dati da una singola fonte. È ancora necessario definire le dipendenze dei dati nel programma e definire esplicitamente le parti di una transazione che possono essere commutate in modo sicuro.
STM ti salva da deadlock e quasi tutte le occorrenze di livelock sebbene non ti salvi da errori di concorrenza puoi ancora creare casi in cui una transazione fallirà perché manca le risorse per mantenere la cronologia ma la parte importante è che gli errori di sarà esplicito e potrai recuperare da loro

+0

Sì! STM = Memoria transazionale software. È un buon lavoro da cercare se vuoi sapere di più su come funziona. –

+2

in Clojure STM, i lettori non devono nemmeno aspettare altri scrittori (a meno che non vogliano fare una lettura transazionale per ottenere un'istantanea coerente su più riferimenti) – mikera

+0

'I lettori non devono mai aspettare altri lettori 'Nel mondo imperativo, i blocchi di lettura/scrittura forniscono questa funzionalità :) – vemv

2

Finché scriverai programmi strettamente sequenziali (fai A, poi B, poi C; finito!) non hai problemi di concorrenza, e i meccanismi di concorrenza di un linguaggio rimangono irrilevanti .

Quando ti diplomi dai programmi di "esercizio di programmazione" a cose del mondo reale, molto presto ti imbatti in problemi la cui soluzione è il multi-threading (o qualsiasi altro sapore di concorrenza che hai a disposizione).

Caso: programmi con una GUI. Supponi di scrivere un editor con il controllo ortografico. Si desidera che il correttore ortografico esegua tranquillamente il suo compito in background, tuttavia si desidera che la GUI accetti facilmente l'input dell'utente. Quindi esegui queste due attività come thread separati.

Caso: di recente ho scritto un programma (per lavoro) che raccoglie le statistiche da due file di registro e li scrive in un database. Ogni file richiede circa 3 minuti per l'elaborazione. Ho spostato questi processi in due thread che corrono fianco a fianco, tagliando il tempo di elaborazione totale da 6 minuti a poco più di 3.

Caso: Scientific/ingegneria del software di simulazione. Ci sono un sacco di problemi che vengono risolti calcolando un certo effetto (flusso di calore, diciamo) in ogni punto di una griglia tridimensionale che rappresenta il soggetto del test (nucleo stellare, esplosione nucleare, dispersione geografica di una popolazione di insetti ...). Fondamentalmente lo stesso calcolo viene eseguito in ogni punto e in molti punti, quindi ha senso farlo in parallelo.

In tutti questi casi e molti altri, ogni volta che due processi informatici accedono alla stessa memoria (= variabili, se lo si desidera) all'incirca nello stesso tempo, è possibile che interferiscano tra loro e rovinino il lavoro gli uni degli altri. L'enorme branca dell'Informatica che si occupa di "programmazione concorrente" si occupa di idee su come risolvere questo tipo di problema.

Una discussione di partenza ragionevolmente utile di questo argomento si possono trovare in Wikipedia.

0

Tale "concorrenza senza blocco" non è realmente una funzione di una lingua ; piuttosto, è una funzionalità di una piattaforma o di un ambiente di runtime, e guai sarà la lingua che non si farà di mezzo per darti accesso a queste strutture.

Pensare alle transazioni tra concorrenza basata su lock e lock-free è analogo al problema del valutatore metacircolare: si possono implementare blocchi in termini di operazioni atomiche (ad es. Confrontare-e-swap o CAS) e si può implementare operazioni atomiche in termini di serrature. Quale dovrebbe essere in fondo?

5

Il più grande è che i blocchi non compongono.

Mentre è banale scrivere codice con una semplice strategia di blocco (ad esempio inserirla in una classe Java sincronizzata .....), diventa esponenzialmente più complicato quando si inizia a bloccare più oggetti e si inizia a creare transazioni complesse che combinano diverse operazioni bloccate. Si possono verificare deadlock, le prestazioni soffrono, la logica di blocco inizia a rendere il codice estremamente complicato e ad un certo punto il codice inizia a diventare non mantenibile.

Questi problemi diventeranno evidenti a chiunque debba costruire un sistema concorrente ampio e complesso (e risolverli è stata una delle principali motivazioni per Rich Hickey nella creazione di Clojure).

La seconda questione è prestazioni.

Sia bloccaggio e STM chiaramente imporre sovraccarico. Ma in alcuni casi importanti il ​​sovraccarico dell'STM può essere molto più basso.

In particolare, la concorrenza senza blocco (come con Clojure STM) di solito implica che i lettori non siano danneggiati da altri thread (compresi i writer!) Se accedono ai dati al di fuori di una transazione. Questo può essere una grande vittoria nel caso abbastanza comune che le letture non hanno bisogno di essere transazionali e superano drammaticamente le scritture (si pensi alla maggior parte delle applicazioni web .....). Le letture non transazionali di un riferimento STM in Clojure sono essenzialmente esenti da sovraccarico.

+0

'Le letture non transazionali di un riferimento STM in Clojure sono essenzialmente esenti da sovraccarico. In linea di principio, quindi, le letture transazionali dovrebbero essere lette? Doc dice "I lettori e i pendolari non bloccheranno mai scrittori, pendolari o altri lettori". – vemv