Clojure för funktionell programmering och JVM-backendutveckling · Lektion

Software Transactional Memory (STM)

Förstå hur Clojures STM tillhandahåller atomiska, konsistenta, isolerade och beständiga (ACID) transaktioner för delat tillstånd.

Lektion 2 av 411 steg

Software Transactional Memory (STM) är en gratis lektion i Clojure för funktionell programmering och JVM-backendutveckling på CoddyKit. Detta är lektion 2 av 4. Ni kan läsa hela lektionen gratis nedan och sedan öva praktiskt i webbläsaren med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt. Den ingår i lärvägen för Clojure för funktionell programmering och JVM-backendutveckling, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i Clojure för funktionell programmering och JVM-backendutveckling innehåller totalt 4 lektioner.

Vad är Software Transactional Memory?

Föreställ er en banköverföring: ni vill inte att pengar ska försvinna eller uppstå ur tomma intet. Hela operationen ska antingen lyckas eller misslyckas helt.

Software Transactional Memory (STM) i Clojure ger en liknande garanti vid hantering av delat, föränderligt tillstånd i samtidiga program.

  • Det fungerar som ett litet transaktionssystem för applikationens minne.
  • Det säkerställer att operationer på delade data sker enligt principen "allt eller inget".

Varför behöver vi STM?

Vid samtidig programmering kan flera delar av koden försöka ändra samma data samtidigt. Det kan leda till:

  • Race conditions: Resultatet beror på den oförutsägbara tidsordningen mellan operationerna.
  • Inkonsekvent tillstånd: Data blir förstörd eller endast delvis uppdaterad.

STM hjälper till att förhindra dessa problem genom att samordna åtkomsten till delade data och säkerställa dataintegriteten.

Introduktion till Clojures `Ref`s

Clojures STM hanterar särskilda databehållare som kallas Refs. Till skillnad från vanliga variabler är Refs utformade för transaktionella uppdateringar.

  • En Ref innehåller ett värde som kan ändras, men endast inom en transaktion.
  • Ni skapar en Ref med ett initialt värde med hjälp av (ref initial-value).

Tänk på en Ref som ett säkert valv för era data, som endast öppnas för transaktioner.

Atomära uppdateringar med `dosync`

För att utföra operationer på Refs måste ni omsluta dem med makrot dosync.

  • dosync definierar ett transaktionsblock.
  • Alla ändringar av Refs inuti dosync behandlas som en enda atomär enhet.
  • Om någon del av transaktionen misslyckas återställs alla ändringar.

Detta säkerställer att era data förblir konsekventa även vid samtidig åtkomst.

Ändra `Ref`s: `alter`

Inuti ett dosync-block använder ni alter för att ändra värdet på en Ref.

(alter a-ref update-fn & args)

  • update-fn är en funktion som tillämpas på det aktuella värdet i Ref.
  • & args är ytterligare argument som skickas till update-fn.
  • alter försöker köra transaktionen igen om en konflikt upptäcks, det vill säga om en annan transaktion ändrar samma Ref.

`dosync` och `alter` i praktiken

Det här exemplet visar hur `dosync` och `alter` fungerar tillsammans. Vi uppdaterar en `Ref` flera gånger inom en transaktion.

(def balance (ref 100))

(defn deposit [amount]
  (dosync
    (println "Current balance (inside transaction):" @balance)
    (alter balance + amount)
    (println "New balance (inside transaction):" @balance)))

(defn -main []
  (println "Initial balance:" @balance)
  (deposit 50)
  (println "Final balance:" @balance))

(-main)

`commute` för oberoende ändringar

Ibland spelar operationernas ordning ingen roll, till exempel när ni lägger till något i en lista eller räknar. För sådana operationer använder ni commute i stället för alter.

(commute a-ref update-fn & args)

  • commute markerar en uppdatering som "kommutativ".
  • Det kan minska risken för att transaktioner måste köras om, vilket förbättrar prestandan.
  • Det fungerar bäst för operationer där `(f (f x a) b)` är samma som `(f (f x b) a)`.

`commute` med flera trådar

Här är ett exempel där flera trådar samtidigt ökar en räknare med hjälp av `commute`. Det visar hur STM hanterar delat tillstånd säkert och effektivt.

(def counter (ref 0))

(defn increment-counter []
  (dosync
    (commute counter inc)))

(defn -main []
  (println "Initial counter:" @counter)
  (let [futures (doall (for [_ (range 10)]
                         (future (dotimes [_ 100] (increment-counter)))))]
    (doseq [f futures] @f)) ; Wait for all futures to complete
  (println "Final counter:" @counter))

(-main)

STM:s ACID-garantier

Clojures STM ger starka garantier som ofta sammanfattas med akronymen ACID:

  • Atomicitet: Allt eller inget. En transaktion slutförs antingen helt eller misslyckas helt.
  • Konsekvens: Transaktioner förflyttar data från ett giltigt tillstånd till ett annat giltigt tillstånd.
  • Isolering: Samtidiga transaktioner verkar köras sekventiellt, vilket förhindrar störningar.
  • Varaktighet: (Mindre tillämpligt på STM direkt i minnet, men underförstått vid en lyckad bekräftelse.) När en transaktion har bekräftats är ändringarna bestående.

Snabbtest om STM

Ta en titt på följande Clojure-kod:

(def data (ref []))

(defn add-item [item]
  (dosync
    (alter data conj item)))

(add-item 10)
(add-item 20)

(println @data)

Vad blir den slutliga utskriften från (println @data)?

Repetition av STM och mer därtill

I den här lektionen utforskade vi Clojures kraftfulla system för Software Transactional Memory (STM).

  • Vi lärde oss om Refs för hantering av delat tillstånd.
  • Makrot dosync säkerställer atomära transaktioner.
  • alter uppdaterar Refs med konfliktdetektering och nya försök.
  • commute optimerar uppdateringar för kommutativa operationer.
  • STM ger ACID-garantier för robust samtidighet.

Nästa gång tittar vi på andra samtidighetsprimitiver, som Promises och Futures, för asynkrona operationer!

Gratis att börja

Lär dig Clojure med en AI-lärare – gratis

Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.

Kurser
12
Lektioner
48

Vanliga frågor

Är lektionen ”Software Transactional Memory (STM)” gratis?

Ja – hela texten till ”Software Transactional Memory (STM)” kan läsas gratis här på webben. Om Ni vill öva interaktivt med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt och låsa upp resten av kursen i Clojure för funktionell programmering och JVM-backendutveckling, kan Ni uppgradera till CoddyKit PRO. Kursen i Clojure för funktionell programmering och JVM-backendutveckling innehåller totalt 4 lektioner.

Vad lär jag mig i ”Software Transactional Memory (STM)”?

Förstå hur Clojures STM tillhandahåller atomiska, konsistenta, isolerade och beständiga (ACID) transaktioner för delat tillstånd. Ni övar på Clojure för funktionell programmering och JVM-backendutveckling med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.

Behöver jag någon erfarenhet för att börja lära mig Clojure för funktionell programmering och JVM-backendutveckling?

Du behöver inga förkunskaper. Utbildningen i Clojure för funktionell programmering och JVM-backendutveckling på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 2 av 4.

Hur lång tid tar lektionen ”Software Transactional Memory (STM)”?

De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.

Kan jag skriva och köra kod i den här Clojure för funktionell programmering och JVM-backendutveckling-lektionen?

Ja. Varje Clojure för funktionell programmering och JVM-backendutveckling-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.

Alla lektioner i den här kursen

  1. Refs, Agents och Atoms för tillstånd
  2. Software Transactional Memory (STM)
  3. Promises, Futures och asynkrona operationer
  4. core.async-kanaler och go-block
← Tillbaka till Clojure för funktionell programmering och JVM-backendutveckling