Composability Esempio di memoria transazionale del software

11

Uno dei principali vantaggi della memoria transazionale del software che viene sempre menzionata è la componibilità e la modularità. Diversi frammenti possono essere combinati per produrre componenti più grandi. Nei programmi basati su lock, spesso questo non è il caso.

Sto cercando un semplice esempio che illustri questo con un codice reale. Preferirei un esempio in Clojure, ma anche Haskell va bene. Punti bonus se nell'esempio è presente anche un codice basato su lock che non può essere composto facilmente.

    
posta dbyrne 01.04.2011 - 22:29
fonte

1 risposta

9

Supponi di avere alcuni conti bancari:

(def accounts 
 [(ref 0) 
  (ref 10) 
  (ref 20) 
  (ref 30)])

E una funzione "trasferimento" atomico:

(defn transfer [src-account dest-account amount]
  (dosync
    (alter dest-account + amount)
    (alter src-account - amount)))

Che funziona come segue:

(transfer (accounts 1) (accounts 0) 5)

(map deref accounts)
=> (5 5 20 30)

È quindi possibile comporre facilmente la funzione di trasferimento per creare una transazione di livello superiore, ad esempio il trasferimento da più account:

(defn transfer-from-all [src-accounts dest-account amount]
  (dosync
    (doseq [src src-accounts] 
      (transfer src dest-account amount))))

(transfer-from-all 
  [(accounts 0) (accounts 1) (accounts 2)] 
  (accounts 3) 
  5)

(map deref accounts)
=> (0 0 15 45)

Si noti che tutti i trasferimenti multipli avvenivano in un'unica transazione combinata, cioè era possibile "comporre" le transazioni minori.

Per fare ciò con i blocchi si complicherebbe molto rapidamente: supponendo che gli account dovessero essere bloccati individualmente, bisognerebbe fare qualcosa come stabilire un protocollo sull'ordine di acquisizione dei blocchi per evitare deadlock. È molto facile fare un errore difficile da rilevare. STM ti salva da tutto questo dolore.

    
risposta data 06.04.2011 - 22:47
fonte

Leggi altre domande sui tag