Funktionel programmering i Clojure og backendudvikling på JVM · Lektion

Promises, futures og asynkrone operationer

Udforsk mønstre til asynkron programmering i Clojure, så De kan håndtere langvarige opgaver og ikke-blokerende I/O.

Lektion 3 af 411 trin

Promises, futures og asynkrone operationer er en gratis Funktionel programmering i Clojure og backendudvikling på JVM-lektion på CoddyKit. Dette er lektion 3 af 4. Du kan læse hele lektionen gratis nedenfor — og derefter øve dig praktisk i browseren med en indbygget kodeeditor og en AI-vejleder, der er tilgængelig døgnet rundt. Den er en del af læringsforløbet i Funktionel programmering i Clojure og backendudvikling på JVM, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. Funktionel programmering i Clojure og backendudvikling på JVM-kurset indeholder 4 lektioner i alt.

Introduktion til asynkron programmering

Velkommen! I denne lektion udforsker vi asynkron programmering i Clojure. Det er vigtigt, når du bygger responsive applikationer, der ikke fryser, mens de venter på langvarige opgaver.

Asynkrone opgaver kører i "baggrunden", så dit hovedprogram kan fortsætte uden afbrydelser. Når baggrundsopgaven er færdig, leverer den sit resultat.

Blokerende kontra ikke-blokerende

Forestil dig, at du henter data fra en langsom server. En blokerende handling får din applikation til at vente, indtil dataene ankommer. I mellemtiden kan der ikke ske noget andet.

En ikke-blokerende handling starter hentningen, men giver straks kontrollen tilbage til din applikation. Din applikation kan derefter gøre andre ting og behandle dataene, når de er tilgængelige.

Clojures makro `future`

Clojure har makroen future, som kører en beregning i en separat tråd. Det gør beregningen asynkron og ikke-blokerende set fra den kaldende kode.

future returnerer straks et "future"-objekt, som er en pladsholder for det endelige resultat.

Brug af `future` til asynkrone opgaver

Lad os se future i praksis. Vi simulerer en langvarig opgave ved hjælp af Thread/sleep. Bemærk, hvordan meddelelsen "Future started" vises med det samme.

(ns my-app.core
  (:gen-class))

(defn -main
  "Demonstrates a simple future."
  [& args]
  (println "Main thread: Starting future...")
  (let [f (future
            (println "  Future thread: Working...")
            (Thread/sleep 2000) ; Simulate work
            (println "  Future thread: Done!")
            "Result from Future")]
    (println "Main thread: Future started, continuing...")
    ; We'll learn how to get the result next!
    (Thread/sleep 1000) ; Let main thread do other work
    (println "Main thread: End of main.")))

Hent resultater fra `future`

Hvis du vil hente den faktiske værdi fra en future, skal du dereferere den. Du kan bruge læsermakroen @ eller funktionen deref.

Hvis beregningen i future-objektet ikke er færdig endnu, blokerer derefereringen den aktuelle tråd, indtil resultatet er klar.

(ns my-app.core
  (:gen-class))

(defn -main
  "Dereferencing a future."
  [& args]
  (println "Main thread: Starting future...")
  (let [f (future
            (println "  Future thread: Working...")
            (Thread/sleep 2000)
            "Long Task Complete")]
    (println "Main thread: Future launched.")
    (println "Main thread: Doing other work...")
    (Thread/sleep 500)
    (println "Main thread: Now waiting for future result...")
    (let [result @f] ; Dereference the future
      (println "Main thread: Future result:" result))
    (println "Main thread: All done!")))

Clojures funktion `promise`

Hvor future kører en beregning, er en promise en pladsholder for en værdi, der senere vil blive leveret, som regel af en anden tråd eller en ekstern hændelse.

Tænk på den som en tom kasse, som en anden fylder. Du kan vente på, at kassen bliver fyldt, ved at dereferere den.

Levering og dereferering af en promise

Funktionen deliver bruges til at lægge en værdi i en promise. Når en promise er blevet leveret, kan dens værdi ikke ændres.

Dereferering af en promise fungerer ligesom med en future: Den blokerer, indtil en værdi er leveret.

(ns my-app.core
  (:gen-class))

(defn -main
  "Delivering and dereferencing a promise."
  [& args]
  (let [p (promise)]
    (println "Main thread: Created a promise.")
    (future
      (println "  Future thread: Doing async work...")
      (Thread/sleep 1500)
      (let [val "Value from Future!"]
        (println "  Future thread: Delivering value to promise.")
        (deliver p val)))
    (println "Main thread: Waiting for promise to be delivered...")
    (let [result @p] ; Blocks until 'deliver' is called
      (println "Main thread: Promise received:" result))
    (println "Main thread: Program finished.")))

Future og promise sammen

future og promise arbejder ofte sammen. En future kan udføre en kompleks beregning og derefter deliver dens resultat til en promise, som så kan hentes af en anden del af din applikation.

Dette mønster er nyttigt til koordinering mellem forskellige asynkrone opgaver eller tråde.

(ns my-app.core
  (:gen-class))

(defn long-calculation []
  (println "  Calculation: Starting...")
  (Thread/sleep 2500) ; Simulate heavy work
  (println "  Calculation: Finished.")
  (* 123 456))

(defn -main
  "Coordinating with future and promise."
  [& args]
  (let [calc-promise (promise)]
    (println "Main: Kicking off calculation...")
    (future ; Run calculation in a separate thread
      (let [result (long-calculation)]
        (deliver calc-promise result)))
    (println "Main: Calculation started. Doing other things...")
    (Thread/sleep 1000)
    (println "Main: Still doing other things...")
    (println "Main: Waiting for calculation result...")
    (let [final-result @calc-promise]
      (println "Main: Received final result:" final-result))
    (println "Main: Done.")))

Håndtering af fejl i asynkrone opgaver

Når der opstår en undtagelse i en future, eller før en promise er leveret, kastes undtagelsen igen i den tråd, der derefererer future- eller promise-objektet.

Det giver dig mulighed for at håndtere fejl i din hovedtråd, selv hvis de stammer fra en asynkron opgave.

Hurtigt tjek: Asynkron adfærd

Se på følgende Clojure-kodestykke:

(let [f (future (Thread/sleep 1000) "Async Result")]
  (println "Started")
  (Thread/sleep 500)
  (println "Waiting...")
  (let [result @f]
    (println "Got:" result)))

Hvad er den *mindste* samlede tid, før "Got: Async Result" udskrives?

Opsummering: Promises, Futures og asynkronitet

  • Asynkron programmering gør det muligt for opgaver at køre uden at blokere hovedprogrammets forløb.
  • Clojures makro future kører en beregning i en separat tråd og returnerer straks en pladsholder.
  • Funktionen promise opretter en pladsholder, som senere kan få leveret en værdi med deliver, ofte fra en anden tråd eller en ekstern kilde.
  • Både future og promise derefereres (med @ eller deref) for at hente deres værdier og blokerer, hvis værdien ikke er klar.
  • Undtagelser i asynkrone opgaver kastes igen ved dereferering.
Gratis at komme i gang

Lær Clojure med en AI-underviser — gratis

Skriv og kør rigtig kode i din browser, få øjeblikkelig hjælp fra en AI-underviser døgnet rundt, og fortsæt, hvor du slap, på web eller i appen.

Kurser
12
Lektioner
48

Ofte stillede spørgsmål

Er lektionen “Promises, futures og asynkrone operationer” gratis?

Ja — hele teksten til “Promises, futures og asynkrone operationer” kan læses gratis her på nettet. Hvis du vil øve dig interaktivt med en indbygget kodeeditor og en AI-vejleder døgnet rundt og få adgang til resten af Funktionel programmering i Clojure og backendudvikling på JVM-kurset, skal du opgradere til CoddyKit PRO. Funktionel programmering i Clojure og backendudvikling på JVM-kurset indeholder 4 lektioner i alt.

Hvad lærer jeg i “Promises, futures og asynkrone operationer”?

Udforsk mønstre til asynkron programmering i Clojure, så De kan håndtere langvarige opgaver og ikke-blokerende I/O. Du øver dig i Funktionel programmering i Clojure og backendudvikling på JVM med praktisk kode, som du kører direkte i browseren, og en AI-vejleder døgnet rundt besvarer dine spørgsmål, mens du arbejder dig gennem lektionen.

Skal jeg have erfaring for at begynde på Funktionel programmering i Clojure og backendudvikling på JVM?

Der kræves ingen tidligere erfaring. Funktionel programmering i Clojure og backendudvikling på JVM på CoddyKit er tilrettelagt for både begyndere og øvede, så du kan starte her eller fra begyndelsen og lære i dit eget tempo. Dette er lektion 3 af 4.

Hvor lang tid tager lektionen “Promises, futures og asynkrone operationer”?

De fleste CoddyKit-lektioner tager cirka 5–10 minutter. Hver lektion er kort og interaktiv, så du gør løbende fremskridt og kan fortsætte, hvor du slap – på både web og app.

Kan jeg skrive og køre kode i denne Funktionel programmering i Clojure og backendudvikling på JVM-lektion?

Ja. Alle Funktionel programmering i Clojure og backendudvikling på JVM-lektioner har en indbygget kodeeditor, så du kan skrive og køre rigtig kode direkte i din browser og få øjeblikkelig feedback fra AI – uden lokal opsætning.

Alle lektioner i dette kursus

  1. Refs, agents og atoms til tilstand
  2. Software Transactional Memory (STM)
  3. Promises, futures og asynkrone operationer
  4. core.async-kanaler og go-blokke
← Tilbage til Funktionel programmering i Clojure og backendudvikling på JVM